private static Symbol getOnlyMember(VisitorState state, Type type, String name) { return getOnlyElement(type.tsym.members().getSymbolsByName(state.getName(name))); }
private static ImmutableList<String> containerOf(VisitorState state, Compound attr) { Attribute m = attr.member(state.getName("containerOf")); if (m == null) { return ImmutableList.of(); } ImmutableList.Builder<String> containerOf = ImmutableList.builder(); m.accept( new SimpleAnnotationValueVisitor8<Void, Void>() { @Override public Void visitString(String s, Void unused) { containerOf.add(s); return null; } @Override public Void visitArray(List<? extends AnnotationValue> list, Void unused) { for (AnnotationValue value : list) { value.accept(this, null); } return null; } }, null); return containerOf.build(); }
/** Returns true if the given method symbol has a {@code @Test(expected=...)} annotation. */ private static boolean isExpectedExceptionTest(MethodSymbol sym, VisitorState state) { Compound attribute = sym.attribute(state.getSymbolFromString(JUnitMatchers.JUNIT4_TEST_ANNOTATION)); if (attribute == null) { return false; } return attribute.member(state.getName("expected")) != null; }
private static boolean isProtoRepeatedFieldCountMethod(ExpressionTree tree, VisitorState state) { // Instance method, on proto class, named `get<Field>Count`. if (!PROTO_METHOD_NAMED_GET_COUNT.matches(tree, state)) { return false; } // Make sure it's the count method for a repeated field, not the get method for a non-repeated // field named <something>_count, by checking for other methods on the repeated field. MethodSymbol methodCallSym = getSymbol((MethodInvocationTree) tree); if (methodCallSym == null) { return false; } Scope protoClassMembers = methodCallSym.owner.members(); java.util.regex.Matcher getCountRegexMatcher = PROTO_COUNT_METHOD_PATTERN.matcher(methodCallSym.getSimpleName().toString()); if (!getCountRegexMatcher.matches()) { return false; } String fieldName = getCountRegexMatcher.group(1); return protoClassMembers.findFirst(state.getName("get" + fieldName + "List")) != null; }
private static Set<Modifier> getIncompatibleModifiers(AnnotationTree tree, VisitorState state) { for (Attribute.Compound c : ASTHelpers.getSymbol(tree).getAnnotationMirrors()) { if (((TypeElement) c.getAnnotationType().asElement()) .getQualifiedName() .contentEquals(GUAVA_ANNOTATION)) { @SuppressWarnings("unchecked") List<Attribute.Enum> modifiers = (List<Attribute.Enum>) c.member(state.getName("value")).getValue(); return ImmutableSet.copyOf( Iterables.transform( modifiers, (Attribute.Enum input) -> Modifier.valueOf(input.getValue().name.toString()))); } } IncompatibleModifiers annotation = ASTHelpers.getAnnotation(tree, IncompatibleModifiers.class); if (annotation != null) { return ImmutableSet.copyOf(annotation.value()); } return ImmutableSet.of(); }
private static Symbol getFinalizer(VisitorState state, ClassSymbol enclosing) { Type finalizerType = state.getTypeFromString("com.google.common.labs.base.Finalizer"); Optional<VarSymbol> finalizerField = state.getTypes().closure(enclosing.asType()).stream() .flatMap(s -> getFields(s.asElement())) .filter(s -> ASTHelpers.isSameType(finalizerType, s.asType(), state)) .findFirst(); if (finalizerField.isPresent()) { return finalizerField.get(); } return ASTHelpers.resolveExistingMethod( state, enclosing.enclClass(), state.getName("finalize"), /* argTypes= */ ImmutableList.of(), /* tyargTypes= */ ImmutableList.of()); }
state, thisClassSymbol, state.getName("read"), ImmutableList.of(byteArrayType, intType, intType), ImmutableList.of());
|| (!isWildCard && !sym.getQualifiedName() .equals(state.getName(methodName)))) { // methodName doesn't match return false;
private Optional<String> generateFix( MethodInvocationTree methodInvocation, boolean negated, VisitorState state) { String methodName = ASTHelpers.getSymbol(methodInvocation).getQualifiedName().toString(); String hasMethod = methodName.replaceFirst("get", "has"); // proto3 does not generate has methods for scalar types, e.g. ByteString and String. // Do not provide a replacement in these cases. Set<MethodSymbol> hasMethods = ASTHelpers.findMatchingMethods( state.getName(hasMethod), ms -> ms.params().isEmpty(), getType(getReceiver(methodInvocation)), state.getTypes()); if (hasMethods.isEmpty()) { return Optional.empty(); } String replacement = replaceLast(methodInvocation.toString(), methodName, hasMethod); return Optional.of(negated ? ("!" + replacement) : replacement); }
/** * Determines whether a symbol has an annotation of the given type. This includes annotations * inherited from superclasses due to {@code @Inherited}. * * @param annotationClass the binary class name of the annotation (e.g. * "javax.annotation.Nullable", or "some.package.OuterClassName$InnerClassName") * @return true if the symbol is annotated with given type. */ public static boolean hasAnnotation(Symbol sym, String annotationClass, VisitorState state) { if (sym == null) { return false; } // normalize to non-binary names annotationClass = annotationClass.replace('$', '.'); Name annotationName = state.getName(annotationClass); if (hasAttribute(sym, annotationName)) { return true; } if (isInherited(state, annotationClass)) { while (sym instanceof ClassSymbol) { if (hasAttribute(sym, annotationName)) { return true; } sym = ((ClassSymbol) sym).getSuperclass().tsym; } } return false; }
/** Finds a declaration with the given name and type that is in scope at the current location. */ @Nullable public static Symbol findIdent(String name, VisitorState state, KindSelector kind) { ClassType enclosingClass = ASTHelpers.getType(state.findEnclosing(ClassTree.class)); if (enclosingClass == null || enclosingClass.tsym == null) { return null; } Env<AttrContext> env = Enter.instance(state.context).getClassEnv(enclosingClass.tsym); MethodTree enclosingMethod = state.findEnclosing(MethodTree.class); if (enclosingMethod != null) { env = MemberEnter.instance(state.context).getMethodEnv((JCMethodDecl) enclosingMethod, env); } try { Method method = Resolve.class.getDeclaredMethod("findIdent", Env.class, Name.class, KindSelector.class); method.setAccessible(true); Symbol result = (Symbol) method.invoke(Resolve.instance(state.context), env, state.getName(name), kind); return result.exists() ? result : null; } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage(), e); } }
@Override public Void visitIdentifier(IdentifierTree identifierTreeX, Void aVoid) { JCIdent identifierTree = (JCIdent) identifierTreeX; Symbol symbol = getSymbol(identifierTree); if (variableDecl.sym.equals(symbol) && !isLeftSideOfAssignment(identifierTree)) { TreePath idPath = TreePath.getPath(compilationUnit, identifierTree); Tree parent = idPath.getParentPath().getLeaf(); boolean callDirectlyOnFramework = shouldCallDirectlyOnFramework(idPath); JCTree replaceNode; if (parent instanceof JCFieldAccess && !callDirectlyOnFramework) { JCFieldAccess fieldAccess = (JCFieldAccess) parent; JCMethodInvocation newShadowOfCall = createSyntheticShadowAccess(shadowOfCall, newVarName, symbol, state); replaceFieldSelected(fieldAccess, newShadowOfCall, state); replaceNode = newShadowOfCall; } else { identifierTree.name = state.getName(newVarName); identifierTree.sym.name = state.getName(newVarName); replaceNode = identifierTree; } String replaceWith = callDirectlyOnFramework ? newVarName : shadowOfCall.getMethodSelect() + "(" + newVarName + ")"; possibleFixes.put( replaceNode, possibleFixes.new ReplacementFix(identifierTree, replaceWith)); } return super.visitIdentifier(identifierTree, aVoid); }
state, symbol, state.getName("hashCode"), ImmutableList.<Type>of(), ImmutableList.<Type>of());
private static JCMethodInvocation createSyntheticShadowAccess( MethodInvocationTree shadowOfCall, String newFieldName, Symbol originalSymbol, VisitorState state) { TreeMaker treeMaker = state.getTreeMaker(); Symbol newSymbol = createSymbol(originalSymbol, state.getName(newFieldName), ((JCExpression) shadowOfCall.getArguments().get(0)).type); JCExpression methodSelect = (JCExpression) shadowOfCall.getMethodSelect(); if (methodSelect instanceof JCIdent) { // clone so start pos can be changed... methodSelect = treeMaker.Ident(((JCIdent) shadowOfCall.getMethodSelect()).sym); } JCMethodInvocation callShadowOf = treeMaker.Apply( null, methodSelect, com.sun.tools.javac.util.List.of(createIdent(treeMaker, newSymbol))); callShadowOf.type = ((JCMethodInvocation) shadowOfCall).type; return callShadowOf; }
/** * @param symStr the string representation of a symbol * @return the Symbol object, or null if it cannot be found */ // TODO(cushon): deal with binary compat issues and return ClassSymbol @Nullable public Symbol getSymbolFromString(String symStr) { symStr = inferBinaryName(symStr); Name name = getName(symStr); Modules modules = Modules.instance(context); boolean modular = modules.getDefaultModule() != getSymtab().noModule; if (!modular) { return getSymbolFromString(getSymtab().noModule, name); } for (ModuleSymbol msym : Modules.instance(context).allModules()) { ClassSymbol result = getSymbolFromString(msym, name); if (result != null) { // TODO(cushon): the path where we iterate over all modules is probably slow. // Try to learn some lessons from JDK-8189747, and consider disallowing this case and // requiring users to call the getSymbolFromString(ModuleSymbol, Name) overload instead. return result; } } return null; }
MethodSymbol hashCode = null; final Types types = state.getTypes(); Name equalsName = state.getName("equals"); Predicate<MethodSymbol> equalsPredicate = new Predicate<MethodSymbol>() { Name hashCodeName = state.getName("hashCode"); Predicate<MethodSymbol> hashCodePredicate = new Predicate<MethodSymbol>() {
state, getSymbol(tree), state.getName("isValidFragment"), ImmutableList.<Type>of(state.getTypeFromString("java.lang.String")), ImmutableList.<Type>of());
/** Check if the method declares or inherits an implementation of .equals() */ public static boolean implementsEquals(Type type, VisitorState state) { Name equalsName = state.getName("equals"); Symbol objectEquals = getOnlyMember(state, state.getSymtab().objectType, "equals"); for (Type sup : state.getTypes().closure(type)) { if (sup.tsym.isInterface()) { continue; } if (ASTHelpers.isSameType(sup, state.getSymtab().objectType, state)) { return false; } Scope scope = sup.tsym.members(); if (scope == null) { continue; } for (Symbol sym : scope.getSymbolsByName(equalsName)) { if (sym.overrides(objectEquals, type.tsym, state.getTypes(), /* checkResult= */ false)) { return true; } } } return false; } }
Set<MethodSymbol> overridesOfEquals = ASTHelpers.findMatchingMethods( state.getName("equals"), equalsPredicate, receiverType, types); Symbol argumentClass = ASTHelpers.getUpperBound(argumentType, state.getTypes()).tsym;
/** Returns true if the given method symbol has a {@code @Test(expected=...)} annotation. */ private static boolean isExpectedExceptionTest(MethodSymbol sym, VisitorState state) { Compound attribute = sym.attribute(state.getSymbolFromString(JUnitMatchers.JUNIT4_TEST_ANNOTATION)); if (attribute == null) { return false; } return attribute.member(state.getName("expected")) != null; }