private static Map<String, PsiType> getCompatibleTypeNames( @NotNull PsiType type, @Nullable PsiType min, PsiManager manager, GlobalSearchScope scope) { if (type instanceof PsiDisjunctionType) type = ((PsiDisjunctionType) type).getLeastUpperBound(); // if initial type is not assignable to min type we don't take into consideration min type. if (min != null && !TypesUtil.isAssignable(min, type, manager, scope)) { min = null; } Map<String, PsiType> map = new LinkedHashMap<String, PsiType>(); final PsiPrimitiveType unboxed = PsiPrimitiveType.getUnboxedType(type); if (unboxed != null) type = unboxed; final Set<PsiType> set = new LinkedHashSet<PsiType>(); set.add(type); while (!set.isEmpty()) { PsiType cur = set.iterator().next(); set.remove(cur); if (!map.containsValue(cur) && (min == null || TypesUtil.isAssignable(min, cur, manager, scope))) { if (isPartiallySubstituted(cur)) { LOG.assertTrue(cur instanceof PsiClassType); PsiClassType rawType = ((PsiClassType) cur).rawType(); map.put(rawType.getPresentableText(), rawType); } else { map.put(cur.getPresentableText(), cur); } for (PsiType superType : cur.getSuperTypes()) { if (!map.containsValue(superType)) { set.add(superType); } } } } return map; }
@Override public void visitBinaryExpression(GrBinaryExpression expression) { final IElementType type = expression.getOperationTokenType(); final GrExpression left = expression.getLeftOperand(); final GrExpression right = expression.getRightOperand(); if (type == mREGEX_FIND || type == mREGEX_MATCH) { final PsiClassType string = TypesUtil.createType(CommonClassNames.JAVA_LANG_STRING, expression); myResult = createSimpleSubTypeResult(string); return; } final GrExpression other = myExpression == left ? right : left; final PsiType otherType = other != null ? other.getType() : null; if (otherType == null) return; if (type == mPLUS && otherType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { final PsiClassType obj = TypesUtil.getJavaLangObject(expression); myResult = createSimpleSubTypeResult(obj); return; } myResult = createSimpleSubTypeResult(otherType); }
public void setType(@Nullable PsiType type) { final GrTypeElement typeElement = getTypeElementGroovy(); if (type == null) { if (typeElement == null) return; if (getModifierList().getModifiers().length == 0) { getModifierList().setModifierProperty(GrModifier.DEF, true); } typeElement.delete(); return; } type = TypesUtil.unboxPrimitiveTypeWrapper(type); GrTypeElement newTypeElement; try { newTypeElement = GroovyPsiElementFactory.getInstance(getProject()).createTypeElement(type); } catch (IncorrectOperationException e) { LOG.error(e); return; } if (typeElement == null) { getModifierList().setModifierProperty(GrModifier.DEF, false); final GrVariable[] variables = getVariables(); if (variables.length == 0) return; newTypeElement = (GrTypeElement) addBefore(newTypeElement, variables[0]); } else { newTypeElement = (GrTypeElement) typeElement.replace(newTypeElement); } JavaCodeStyleManager.getInstance(getProject()).shortenClassReferences(newTypeElement); }
@Override public void applyTransformation(@NotNull TransformationContext context) { if (!(context.getCodeClass() instanceof GroovyScriptClass)) return; GroovyScriptClass scriptClass = (GroovyScriptClass) context.getCodeClass(); LightMethodBuilder mainMethod = new LightMethodBuilder(scriptClass.getManager(), GroovyLanguage.INSTANCE, "main") .setMethodReturnType(PsiType.VOID) .addParameter( "args", new PsiArrayType( PsiType.getJavaLangString( scriptClass.getManager(), scriptClass.getResolveScope()))) .addModifiers(PsiModifier.PUBLIC, PsiModifier.STATIC); LightMethodBuilder runMethod = new LightMethodBuilder(scriptClass.getManager(), GroovyLanguage.INSTANCE, "run") .setMethodReturnType(TypesUtil.getJavaLangObject(scriptClass)) .addModifier(PsiModifier.PUBLIC); context.addMethod(runMethod, true); context.addMethod(mainMethod, true); context.setSuperType(getBaseClassType(scriptClass)); }
@Override public PsiType fun(GrMethodBaseImpl method) { PsiType nominal = method.getNominalType(); if (nominal != null) { if (!(nominal instanceof PsiClassType && hasTypeParametersToInfer((PsiClassType) nominal))) { return nominal; } } if (!GppTypeConverter.hasTypedContext(method)) { LOG.assertTrue(method.isValid(), "invalid method"); final GrOpenBlock block = method.getBlock(); if (block != null) { LOG.assertTrue(block.isValid(), "invalid code block"); PsiType inferred = GroovyPsiManager.inferType(method, new MethodTypeInferencer(block)); if (inferred != null) { if (nominal == null || nominal.isAssignableFrom(inferred)) { return inferred; } } } } if (nominal != null) { return nominal; } return TypesUtil.getJavaLangObject(method); }
public static boolean runContributors( @NotNull PsiType qualifierType, @NotNull PsiScopeProcessor processor, @NotNull PsiElement place, @NotNull ResolveState state) { MyDelegatingScopeProcessor delegatingProcessor = new MyDelegatingScopeProcessor(processor); ensureInit(); final PsiClass aClass = PsiTypesUtil.getPsiClass(qualifierType); if (aClass != null) { for (String superClassName : TypesUtil.getSuperClassesWithCache(aClass).keySet()) { for (NonCodeMembersContributor enhancer : ourClassSpecifiedContributors.get(superClassName)) { ProgressManager.checkCanceled(); enhancer.processDynamicElements(qualifierType, aClass, delegatingProcessor, place, state); if (!delegatingProcessor.wantMore) { return false; } } } } for (NonCodeMembersContributor contributor : ourAllTypeContributors) { ProgressManager.checkCanceled(); contributor.processDynamicElements(qualifierType, aClass, delegatingProcessor, place, state); if (!delegatingProcessor.wantMore) { return false; } } return GroovyDslFileIndex.processExecutors(qualifierType, place, processor, state); }
@Override public void visitBinaryExpression(GrBinaryExpression expression) { super.visitBinaryExpression(expression); if (expression.getOperationTokenType() != GroovyTokenTypes.kIN) return; GrExpression leftOperand = expression.getLeftOperand(); GrExpression rightOperand = expression.getRightOperand(); if (leftOperand == null || rightOperand == null) return; PsiType ltype = leftOperand.getType(); PsiType rtype = rightOperand.getType(); if (ltype == null || rtype == null) return; PsiType component; if (rtype instanceof PsiArrayType) { component = ((PsiArrayType) rtype).getComponentType(); } else if (InheritanceUtil.isInheritor(rtype, CommonClassNames.JAVA_UTIL_COLLECTION)) { component = PsiUtil.substituteTypeParameter(rtype, CommonClassNames.JAVA_UTIL_COLLECTION, 0, false); } else { checkSimpleClasses(ltype, rtype, expression); return; } if (component == null) return; if (TypesUtil.isAssignable( ltype, component, expression.getManager(), expression.getResolveScope(), false)) return; registerError(expression, ltype, rtype); }
@Override @Nullable public PsiType getNominalType() { final GroovyResolveResult resolveResult = advancedResolve(); PsiElement resolved = resolveResult.getElement(); for (GrReferenceTypeEnhancer enhancer : GrReferenceTypeEnhancer.EP_NAME.getExtensions()) { PsiType type = enhancer.getReferenceType(this, resolved); if (type != null) { return type; } } IElementType dotType = getDotTokenType(); if (dotType == GroovyTokenTypes.mMEMBER_POINTER) { return GrClosureType.create(multiResolve(false), this); } if (isDefinitelyKeyOfMap()) { final PsiType type = getTypeFromMapAccess(this); if (type != null) { return type; } } PsiType result = getNominalTypeInner(resolved); if (result == null) return null; result = TypesUtil.substituteAndNormalizeType( result, resolveResult.getSubstitutor(), resolveResult.getSpreadState(), this); return result; }
private static boolean containsAllCases(GrSwitchStatement statement) { final GrCaseSection[] sections = statement.getCaseSections(); for (GrCaseSection section : sections) { if (section.isDefault()) return true; } final GrExpression condition = statement.getCondition(); if (!(condition instanceof GrReferenceExpression)) return false; PsiType type = TypesUtil.unboxPrimitiveTypeWrapper(getNominalTypeNoRecursion(condition)); if (type == null) return false; if (type instanceof PsiPrimitiveType) { if (type == PsiType.BOOLEAN) return sections.length == 2; if (type == PsiType.BYTE || type == PsiType.CHAR) return sections.length == 128; return false; } if (type instanceof PsiClassType) { final PsiClass resolved = ((PsiClassType) type).resolve(); if (resolved != null && resolved.isEnum()) { int enumConstantCount = 0; final PsiField[] fields = resolved.getFields(); for (PsiField field : fields) { if (field instanceof PsiEnumConstant) enumConstantCount++; } if (sections.length == enumConstantCount) return true; } } return false; }
public void visitAssertStatement(GrAssertStatement assertStatement) { final InstructionImpl assertInstruction = startNode(assertStatement); final GrExpression assertion = assertStatement.getAssertion(); if (assertion != null) { assertion.accept(this); InstructionImpl positiveHead = myHead; List<GotoInstruction> negations = collectAndRemoveAllPendingNegations(assertStatement); if (!negations.isEmpty()) { interruptFlow(); reduceAllNegationsIntoInstruction(assertStatement, negations); } GrExpression errorMessage = assertStatement.getErrorMessage(); if (errorMessage != null) { errorMessage.accept(this); } addNode(new ThrowingInstruction(assertStatement)); final PsiType type = TypesUtil.createTypeByFQClassName( CommonClassNames.JAVA_LANG_ASSERTION_ERROR, assertStatement); ExceptionInfo info = findCatch(type); if (info != null) { info.myThrowers.add(myHead); } else { addPendingEdge(null, myHead); } myHead = positiveHead; } finishNode(assertInstruction); }
@Override public GroovyResolveResult[] resolve( GrAssignmentExpressionImpl assignmentExpression, boolean incompleteCode) { final IElementType opType = assignmentExpression.getOperationToken(); if (opType == null || opType == GroovyTokenTypes.mASSIGN) return GroovyResolveResult.EMPTY_ARRAY; final GrExpression lValue = assignmentExpression.getLValue(); final PsiType lType; if (!(lValue instanceof GrIndexProperty)) { lType = lValue.getType(); } else { /* now we have something like map[i] += 2. It equals to map.putAt(i, map.getAt(i).plus(2)) by default map[i] resolves to putAt, but we need getAt(). so this hack is for it =) */ lType = ((GrExpression) lValue.copy()).getType(); } if (lType == null) return GroovyResolveResult.EMPTY_ARRAY; final GrExpression rightOperand = assignmentExpression.getRValue(); PsiType rType = rightOperand == null ? null : rightOperand.getType(); final IElementType operatorToken = TokenSets.ASSIGNMENTS_TO_OPERATORS.get(opType); return TypesUtil.getOverloadedOperatorCandidates( lType, operatorToken, assignmentExpression, new PsiType[] {rType}); }
@Nullable @Override public PsiType fun(GrUnaryExpressionImpl unary) { final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(unary.multiResolve(false)); if (isIncDecNumber(resolveResult)) { return unary.getOperand().getType(); } final PsiType substituted = ResolveUtil.extractReturnTypeFromCandidate(resolveResult, unary, PsiType.EMPTY_ARRAY); if (substituted != null) { return substituted; } GrExpression operand = unary.getOperand(); if (operand == null) return null; final PsiType type = operand.getType(); if (TypesUtil.isNumericType(type)) { return type; } return null; }
@Nullable public static PsiType getExpectedClosureReturnType(GrClosableBlock closure) { final Set<PsiType> expectedTypes = getDefaultExpectedTypes(closure); List<PsiType> expectedReturnTypes = new ArrayList<PsiType>(); for (PsiType expectedType : expectedTypes) { if (!(expectedType instanceof PsiClassType)) return null; final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType) expectedType).resolveGenerics(); final PsiClass resolved = resolveResult.getElement(); if (resolved == null || !(GroovyCommonClassNames.GROOVY_LANG_CLOSURE.equals(resolved.getQualifiedName()))) return null; final PsiTypeParameter[] typeParameters = resolved.getTypeParameters(); if (typeParameters.length != 1) return null; final PsiTypeParameter expected = typeParameters[0]; final PsiType expectedReturnType = resolveResult.getSubstitutor().substitute(expected); if (expectedReturnType == PsiType.VOID || expectedReturnType == null) return null; expectedReturnTypes.add(expectedReturnType); } return TypesUtil.getLeastUpperBoundNullable(expectedReturnTypes, closure.getManager()); }
public void visitTraditionalForClause(GrTraditionalForClause forClause) { if (myExpression.equals(forClause.getCondition())) { myResult = new TypeConstraint[] { new SubtypeConstraint(TypesUtil.getJavaLangObject(forClause), PsiType.BOOLEAN) }; } }
public void visitWhileStatement(GrWhileStatement whileStatement) { if (myExpression.equals(whileStatement.getCondition())) { myResult = new TypeConstraint[] { new SubtypeConstraint(TypesUtil.getJavaLangObject(whileStatement), PsiType.BOOLEAN) }; } }
@Nullable private static PsiType getTypeFromClassRef(@NotNull GrReferenceExpressionImpl ref) { if ("class".equals(ref.getReferenceName())) { return TypesUtil.createJavaLangClassType( GrReferenceResolveUtil.getQualifierType(ref), ref.getProject(), ref.getResolveScope()); } return null; }
@Nullable private static PsiType getTypeFromSpreadOperator(@NotNull GrReferenceExpressionImpl ref) { if (ref.getDotTokenType() == GroovyTokenTypes.mSPREAD_DOT) { return TypesUtil.createType(CommonClassNames.JAVA_UTIL_LIST, ref); } return null; }
private boolean typesAgree(@NotNull PsiType type1, @NotNull PsiType type2) { if (argumentsSupplied() && type1 instanceof PsiArrayType && !(type2 instanceof PsiArrayType)) { type1 = ((PsiArrayType) type1).getComponentType(); } return argumentsSupplied() ? // resolve, otherwise same_name_variants TypesUtil.isAssignableWithoutConversions(type1, type2, myPlace) : type1.equals(type2); }
private static boolean haveDifferentTypes(List<VariableInfo> varInfos) { if (varInfos.size() < 2) return true; Set<String> diffTypes = new HashSet<String>(); for (VariableInfo info : varInfos) { final PsiType t = info.getType(); diffTypes.add(t == null ? null : TypesUtil.unboxPrimitiveTypeWrapper(t).getCanonicalText()); } return diffTypes.size() > 1; }
private static boolean hasOnlyClosureParams(PsiMethod method) { final PsiParameter[] params = method.getParameterList().getParameters(); for (PsiParameter param : params) { final PsiType type = param.getType(); if (!TypesUtil.isClassType(type, GroovyCommonClassNames.GROOVY_LANG_CLOSURE)) { return false; } } return params.length > 0; }
private static PsiType doFun(GrReferenceExpression refExpr) { if (ResolveUtil.isClassReference(refExpr)) { GrExpression qualifier = refExpr.getQualifier(); LOG.assertTrue(qualifier != null); return TypesUtil.createJavaLangClassType( qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope()); } if (PsiUtil.isCompileStatic(refExpr)) { final GroovyResolveResult resolveResult = refExpr.advancedResolve(); final PsiElement resolvedF = resolveResult.getElement(); final PsiType type; if (resolvedF instanceof GrField) { type = ((GrField) resolvedF).getType(); } else if (resolvedF instanceof GrAccessorMethod) { type = ((GrAccessorMethod) resolvedF).getProperty().getType(); } else { type = null; } if (type != null) { return resolveResult.getSubstitutor().substitute(type); } } final PsiElement resolved = refExpr.resolve(); final PsiType nominal = refExpr.getNominalType(); Boolean reassigned = GrReassignedLocalVarsChecker.isReassignedVar(refExpr); if (reassigned != null && reassigned.booleanValue()) { return GrReassignedLocalVarsChecker.getReassignedVarType(refExpr, true); } final PsiType inferred = getInferredTypes(refExpr, resolved); if (inferred == null) { if (nominal == null) { // inside nested closure we could still try to infer from variable initializer. Not sound, // but makes sense if (resolved instanceof GrVariable) { LOG.assertTrue(resolved.isValid()); return ((GrVariable) resolved).getTypeGroovy(); } } return nominal; } if (nominal == null) return inferred; if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) { if (resolved instanceof GrVariable && ((GrVariable) resolved).getTypeElementGroovy() != null) { return nominal; } } return inferred; }
public void visitIfStatement(GrIfStatement ifStatement) { if (myExpression.equals(ifStatement.getCondition())) { myResult = new TypeConstraint[] { new SubtypeConstraint(TypesUtil.getJavaLangObject(ifStatement), PsiType.BOOLEAN) }; } else if (myExpression.equals(ifStatement.getThenBranch()) || myExpression.equals(ifStatement.getElseBranch())) { checkExitPoint(); } }
@NotNull private static PsiClassType getBaseClassType(@NotNull GroovyScriptClass scriptClass) { PsiClassType type = getSuperClassTypeFromBaseScriptAnnotatedVariable(scriptClass); if (type != null) return type; final PsiClassType superClassFromDSL = GroovyDslFileIndex.processScriptSuperClasses(scriptClass.getContainingFile()); if (superClassFromDSL != null) return superClassFromDSL; return TypesUtil.createTypeByFQClassName( GroovyCommonClassNames.GROOVY_LANG_SCRIPT, scriptClass); }
private void getVariantsFromQualifier(@NotNull GrExpression qualifier) { Project project = qualifier.getProject(); PsiType qualifierType = qualifier.getType(); final ResolveState state = ResolveState.initial(); if (qualifierType == null || qualifierType == PsiType.VOID) { if (qualifier instanceof GrReferenceExpression) { PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); if (resolved instanceof PsiPackage || resolved instanceof PsiVariable) { resolved.processDeclarations(myProcessor, state, null, myRefExpr); return; } } getVariantsFromQualifierType(TypesUtil.getJavaLangObject(qualifier), project); } else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { getVariantsFromQualifierType(conjunct, project); } } else if (qualifierType instanceof GrTraitType) { GrTypeDefinition definition = ((GrTraitType) qualifierType).getMockTypeDefinition(); if (definition != null) { PsiClassType classType = JavaPsiFacade.getElementFactory(project).createType(definition); getVariantsFromQualifierType(classType, project); } else { getVariantsFromQualifierType(((GrTraitType) qualifierType).getExprType(), project); for (PsiClassType traitType : ((GrTraitType) qualifierType).getTraitTypes()) { getVariantsFromQualifierType(traitType, project); } } } else { getVariantsFromQualifierType(qualifierType, project); if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) { PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); if (resolved instanceof PsiClass) { // //omitted .class GlobalSearchScope scope = myRefExpr.getResolveScope(); PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, scope); if (javaLangClass != null) { PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters(); if (typeParameters.length == 1) { substitutor = substitutor.put(typeParameters[0], qualifierType); } PsiType javaLangClassType = JavaPsiFacade.getElementFactory(myRefExpr.getProject()) .createType(javaLangClass, substitutor); ResolveUtil.processAllDeclarations(javaLangClassType, myProcessor, state, myRefExpr); } } } } }
@NotNull @Override public GroovyResolveResult[] resolve( @NotNull GrUnaryExpressionImpl unary, boolean incompleteCode) { final GrExpression operand = unary.getOperand(); if (operand == null) return GroovyResolveResult.EMPTY_ARRAY; final PsiType type = operand.getType(); if (type == null) return GroovyResolveResult.EMPTY_ARRAY; return TypesUtil.getOverloadedUnaryOperatorCandidates( type, unary.getOperationTokenType(), operand, PsiType.EMPTY_ARRAY); }
@Nullable private PsiType extractMapValueType( PsiType thisType, PsiType[] argTypes, PsiManager manager, GlobalSearchScope resolveScope) { if (argTypes.length != 1 || !InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_MAP)) return null; final PsiType substituted = substituteTypeParameter(thisType, CommonClassNames.JAVA_UTIL_MAP, 1, true); return TypesUtil.boxPrimitiveType(substituted, manager, resolveScope); }
@Nullable private PsiType extractLastParameterType(GroovyResolveResult candidate) { PsiElement element = candidate.getElement(); if (element instanceof PsiMethod) { PsiParameter[] parameters = ((PsiMethod) element).getParameterList().getParameters(); if (parameters.length > 1) { PsiParameter last = parameters[parameters.length - 1]; return TypesUtil.substituteBoxAndNormalizeType( last.getType(), candidate.getSubstitutor(), candidate.getSpreadState(), this); } } return null; }
@Override public void processDynamicElements( @NotNull PsiType qualifierType, PsiClass aClass, PsiScopeProcessor processor, GroovyPsiElement place, ResolveState state) { ClassHint classHint = processor.getHint(ClassHint.KEY); if (classHint != null && !classHint.shouldProcess(ClassHint.ResolveKind.PROPERTY)) return; String nameHint = ResolveUtil.getNameHint(processor); Map<String, PsiClass> supers = TypesUtil.getSuperClassesWithCache(aClass); PsiElement grCall = place.getParent(); if (grCall instanceof GrMethodCall) { PsiElement grClosure = grCall.getParent(); if (grClosure instanceof GrClosableBlock) { PsiElement contentField = grClosure.getParent(); if (contentField instanceof GrField) { GrField f = (GrField) contentField; if ("content".equals(f.getName()) && f.hasModifierProperty(PsiModifier.STATIC) && f.getContainingClass() == aClass) { Map<String, PsiField> elements = GebUtil.getContentElements(aClass); for (PsiField field : elements.values()) { if (field.getNavigationElement() == place) { return; // Don't resolve variable definition. } } } } } } for (PsiClass psiClass : supers.values()) { Map<String, PsiField> contentFields = GebUtil.getContentElements(psiClass); if (nameHint == null) { for (Map.Entry<String, PsiField> entry : contentFields.entrySet()) { if (!processor.execute(entry.getValue(), state)) return; } } else { PsiField field = contentFields.get(nameHint); if (field != null) { processor.execute(field, state); return; } } } }
@Override @Nullable public PsiType getReturnType() { if (isConstructor()) { return null; } final PsiType type = getNominalType(); if (type != null) { return type; } return TypesUtil.getJavaLangObject(this); }
private PsiClassType createEnumType() { JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); PsiClass enumClass = facade.findClass(JAVA_LANG_ENUM, getResolveScope()); PsiElementFactory factory = facade.getElementFactory(); if (enumClass != null) { PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; PsiTypeParameter[] typeParameters = enumClass.getTypeParameters(); if (typeParameters.length == 1) { substitutor = substitutor.put(typeParameters[0], factory.createType(this)); } return factory.createType(enumClass, substitutor); } return TypesUtil.createTypeByFQClassName(JAVA_LANG_ENUM, this); }