public void test_metadata_typedef() throws Exception { Source source = addSource( createSource( // "const A = null;", "@A typedef F<A>();")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unitElement = library.getDefiningCompilationUnit(); assertNotNull(unitElement); FunctionTypeAliasElement[] aliases = unitElement.getFunctionTypeAliases(); assertLength(1, aliases); ElementAnnotation[] annotations = aliases[0].getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); CompilationUnit unit = resolveCompilationUnit(source, library); NodeList<CompilationUnitMember> declarations = unit.getDeclarations(); assertSizeOfList(2, declarations); Element expectedElement = ((TopLevelVariableDeclaration) declarations.get(0)) .getVariables() .getVariables() .get(0) .getName() .getStaticElement(); assertInstanceOf(PropertyInducingElement.class, expectedElement); expectedElement = ((PropertyInducingElement) expectedElement).getGetter(); Element actualElement = ((FunctionTypeAlias) declarations.get(1)).getMetadata().get(0).getName().getStaticElement(); assertSame(expectedElement, actualElement); }
/** * Resolve the given source and verify that the arguments in a specific method invocation were * correctly resolved. * * <p>The source is expected to be source for a compilation unit, the first declaration is * expected to be a class, the first member of which is expected to be a method with a block body, * and the first statement in the body is expected to be an expression statement whose expression * is a method invocation. It is the arguments to that method invocation that are tested. The * method invocation can contain errors. * * <p>The arguments were resolved correctly if the number of expressions in the list matches the * length of the array of indices and if, for each index in the array of indices, the parameter to * which the argument expression was resolved is the parameter in the invoked method's list of * parameters at that index. Arguments that should not be resolved to a parameter because of an * error can be denoted by including a negative index in the array of indices. * * @param source the source to be resolved * @param indices the array of indices used to associate arguments with parameters * @throws Exception if the source could not be resolved or if the structure of the source is not * valid */ private void validateArgumentResolution(Source source, int... indices) throws Exception { LibraryElement library = resolve(source); assertNotNull(library); ClassElement classElement = library.getDefiningCompilationUnit().getTypes()[0]; ParameterElement[] parameters = classElement.getMethods()[1].getParameters(); CompilationUnit unit = resolveCompilationUnit(source, library); assertNotNull(unit); ClassDeclaration classDeclaration = (ClassDeclaration) unit.getDeclarations().get(0); MethodDeclaration methodDeclaration = ((MethodDeclaration) classDeclaration.getMembers().get(0)); Block block = ((BlockFunctionBody) methodDeclaration.getBody()).getBlock(); ExpressionStatement statement = (ExpressionStatement) block.getStatements().get(0); MethodInvocation invocation = (MethodInvocation) statement.getExpression(); NodeList<Expression> arguments = invocation.getArgumentList().getArguments(); int argumentCount = arguments.size(); assertEquals(indices.length, argumentCount); for (int i = 0; i < argumentCount; i++) { Expression argument = arguments.get(i); ParameterElement element = argument.getStaticParameterElement(); int index = indices[i]; if (index < 0) { assertNull(element); } else { assertSame(parameters[index], element); } } }
public void test_constructor_initializer_withParenthesizedExpression() throws Exception { CompilationUnit unit = parseCompilationUnit( createSource("class C {", " C() :", " this.a = (b == null ? c : d) {", " }", "}")); NodeList<CompilationUnitMember> declarations = unit.getDeclarations(); assertSize(1, declarations); }
@Override public Void visitCompilationUnit(CompilationUnit node) { ScriptTag scriptTag = node.getScriptTag(); NodeList<Directive> directives = node.getDirectives(); visit(scriptTag); String prefix = scriptTag == null ? "" : " "; visitList(prefix, directives, " "); prefix = scriptTag == null && directives.isEmpty() ? "" : " "; visitList(prefix, node.getDeclarations(), " "); return null; }
private void analyzePossibleConflicts_inLibrary( final RefactoringStatus result, Source unitSource, Source librarySource) { // prepare resolved unit CompilationUnit unit = null; try { unit = context.resolveCompilationUnit(unitSource, librarySource); } catch (AnalysisException e) { } if (unit == null) { return; } // check for conflicts in the unit final SourceRange elementRange = element.getVisibleRange(); unit.accept( new RecursiveAstVisitor<Void>() { @Override public Void visitSimpleIdentifier(SimpleIdentifier node) { Element nameElement = node.getBestElement(); if (nameElement != null && nameElement.getName().equals(newName)) { // duplicate declaration if (haveIntersectingRanges(element, nameElement)) { String message = MessageFormat.format( "Duplicate local {0} ''{1}''.", getElementKindName(nameElement), newName); result.addError(message, new RefactoringStatusContext(nameElement)); return null; } // shadowing referenced element if (elementRange.contains(node.getOffset()) && !node.isQualified()) { nameElement = HierarchyUtils.getSyntheticAccessorVariable(nameElement); String nameElementSourceName = nameElement.getSource().getShortName(); String message = MessageFormat.format( "Usage of {0} ''{1}'' declared in ''{2}'' will be shadowed by renamed {3}.", getElementKindName(nameElement), getElementQualifiedName(nameElement), nameElementSourceName, getElementKindName(element)); result.addError(message, new RefactoringStatusContext(node)); } } return null; } }); }
public void test_localVariable_types_invoked() throws Exception { Source source = addSource( createSource( // "const A = null;", "main() {", " var myVar = (int p) => 'foo';", " myVar(42);", "}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnit unit = getAnalysisContext().getResolvedCompilationUnit(source, library); assertNotNull(unit); final boolean[] found = {false}; final AnalysisException[] thrownException = new AnalysisException[1]; unit.accept( new RecursiveAstVisitor<Void>() { @Override public Void visitSimpleIdentifier(SimpleIdentifier node) { if (node.getName().equals("myVar") && node.getParent() instanceof MethodInvocation) { try { found[0] = true; // check static type Type staticType = node.getStaticType(); assertSame(getTypeProvider().getDynamicType(), staticType); // check propagated type FunctionType propagatedType = (FunctionType) node.getPropagatedType(); assertEquals(getTypeProvider().getStringType(), propagatedType.getReturnType()); } catch (AnalysisException e) { thrownException[0] = e; } } return null; } }); if (thrownException[0] != null) { throw new AnalysisException("Exception", thrownException[0]); } assertTrue(found[0]); }
/** * Return the name of the library that the given part is declared to be a part of, or {@code null} * if the part does not contain a part-of directive. * * @param partSource the source representing the part * @param partUnit the AST structure of the part * @param directivesToResolve a list of directives that should be resolved to the library being * built * @return the name of the library that the given part is declared to be a part of */ private String getPartLibraryName( Source partSource, CompilationUnit partUnit, ArrayList<Directive> directivesToResolve) { for (Directive directive : partUnit.getDirectives()) { if (directive instanceof PartOfDirective) { directivesToResolve.add(directive); LibraryIdentifier libraryName = ((PartOfDirective) directive).getLibraryName(); if (libraryName != null) { return libraryName.getName(); } } } return null; }
@Override public void process(final Context context, final CompilationUnit unit) { NodeList<CompilationUnitMember> declarations = unit.getDeclarations(); // remove NodeList, it is declared in enginelib.dart for (Iterator<CompilationUnitMember> iter = declarations.iterator(); iter.hasNext(); ) { CompilationUnitMember member = iter.next(); if (member instanceof ClassDeclaration) { ClassDeclaration classDeclaration = (ClassDeclaration) member; String name = classDeclaration.getName().getName(); if (name.equals("NodeList") || name.equals("NodeLocator") || name.equals("NodeFoundException")) { iter.remove(); } } } // process nodes unit.accept( new GeneralizingASTVisitor<Void>() { @Override public Void visitMethodDeclaration(MethodDeclaration node) { String name = node.getName().getName(); if ("accept".equals(name) && node.getParameters().getParameters().size() == 1) { node.setReturnType(null); FormalParameter formalParameter = node.getParameters().getParameters().get(0); ((SimpleFormalParameter) formalParameter).getType().setTypeArguments(null); } return super.visitMethodDeclaration(node); } @Override public Void visitMethodInvocation(MethodInvocation node) { if (isMethodInClass( node, "toArray", "com.google.dart.engine.utilities.collection.IntList")) { replaceNode(node, node.getTarget()); return null; } return super.visitMethodInvocation(node); } @Override public Void visitTypeName(TypeName node) { if (node.getName() instanceof SimpleIdentifier) { SimpleIdentifier nameNode = (SimpleIdentifier) node.getName(); String name = nameNode.getName(); if ("IntList".equals(name)) { replaceNode(node, typeName("List", typeName("int"))); return null; } } return super.visitTypeName(node); } private boolean isMethodInClass( MethodInvocation node, String reqName, String reqClassName) { String name = node.getMethodName().getName(); return Objects.equal(name, reqName) && JavaUtils.isMethodInClass(context.getNodeBinding(node), reqClassName); } }); }
@Override public R visitCompilationUnit(CompilationUnit node) { node.visitChildren(this); return null; }
public static Element getElementEnclosingOffset(CompilationUnit unit, final int offset) { final Element result[] = new Element[] {null}; unit.accept( new GeneralizingAstVisitor<Void>() { @Override public Void visitClassDeclaration(ClassDeclaration node) { if (isNodeEnclosingOffset(node)) { result[0] = node.getElement(); return super.visitClassDeclaration(node); } return null; } @Override public Void visitConstructorDeclaration(ConstructorDeclaration node) { if (isNodeEnclosingOffset(node)) { result[0] = node.getElement(); return super.visitConstructorDeclaration(node); } return null; } @Override public Void visitFieldDeclaration(FieldDeclaration node) { if (isNodeEnclosingOffset(node)) { NodeList<VariableDeclaration> variables = node.getFields().getVariables(); if (!variables.isEmpty()) { result[0] = variables.get(0).getElement(); } return super.visitFieldDeclaration(node); } return null; } @Override public Void visitFunctionDeclaration(FunctionDeclaration node) { if (isNodeEnclosingOffset(node)) { result[0] = node.getElement(); return super.visitFunctionDeclaration(node); } return null; } @Override public Void visitMethodDeclaration(MethodDeclaration node) { if (isNodeEnclosingOffset(node)) { result[0] = node.getElement(); return super.visitMethodDeclaration(node); } return null; } @Override public Void visitNode(AstNode node) { if (isNodeEnclosingOffset(node)) { super.visitNode(node); } return null; } private boolean isNodeEnclosingOffset(AstNode node) { return node.getOffset() <= offset && offset <= node.getEnd(); } }); return result[0]; }
/** * Build the library element for the given library. * * @param library the library for which an element model is to be built * @return the library element that was built * @throws AnalysisException if the analysis could not be performed */ public LibraryElementImpl buildLibrary(Library library) throws AnalysisException { CompilationUnitBuilder builder = new CompilationUnitBuilder(); Source librarySource = library.getLibrarySource(); CompilationUnit definingCompilationUnit = library.getDefiningCompilationUnit(); CompilationUnitElementImpl definingCompilationUnitElement = builder.buildCompilationUnit(librarySource, definingCompilationUnit); NodeList<Directive> directives = definingCompilationUnit.getDirectives(); LibraryIdentifier libraryNameNode = null; boolean hasPartDirective = false; FunctionElement entryPoint = findEntryPoint(definingCompilationUnitElement); ArrayList<Directive> directivesToResolve = new ArrayList<Directive>(); ArrayList<CompilationUnitElementImpl> sourcedCompilationUnits = new ArrayList<CompilationUnitElementImpl>(); for (Directive directive : directives) { // // We do not build the elements representing the import and export directives at this point. // That is not done until we get to LibraryResolver.buildDirectiveModels() because we need the // LibraryElements for the referenced libraries, which might not exist at this point (due to // the possibility of circular references). // if (directive instanceof LibraryDirective) { if (libraryNameNode == null) { libraryNameNode = ((LibraryDirective) directive).getName(); directivesToResolve.add(directive); } } else if (directive instanceof PartDirective) { PartDirective partDirective = (PartDirective) directive; StringLiteral partUri = partDirective.getUri(); Source partSource = partDirective.getSource(); if (analysisContext.exists(partSource)) { hasPartDirective = true; CompilationUnit partUnit = library.getAST(partSource); CompilationUnitElementImpl part = builder.buildCompilationUnit(partSource, partUnit); part.setUriOffset(partUri.getOffset()); part.setUriEnd(partUri.getEnd()); part.setUri(partDirective.getUriContent()); // // Validate that the part contains a part-of directive with the same name as the library. // String partLibraryName = getPartLibraryName(partSource, partUnit, directivesToResolve); if (partLibraryName == null) { errorListener.onError( new AnalysisError( librarySource, partUri.getOffset(), partUri.getLength(), CompileTimeErrorCode.PART_OF_NON_PART, partUri.toSource())); } else if (libraryNameNode == null) { // TODO(brianwilkerson) Collect the names declared by the part. If they are all the same // then we can use that name as the inferred name of the library and present it in a // quick-fix. // partLibraryNames.add(partLibraryName); } else if (!libraryNameNode.getName().equals(partLibraryName)) { errorListener.onError( new AnalysisError( librarySource, partUri.getOffset(), partUri.getLength(), StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, libraryNameNode.getName(), partLibraryName)); } if (entryPoint == null) { entryPoint = findEntryPoint(part); } directive.setElement(part); sourcedCompilationUnits.add(part); } } } if (hasPartDirective && libraryNameNode == null) { errorListener.onError( new AnalysisError(librarySource, ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART)); } // // Create and populate the library element. // LibraryElementImpl libraryElement = new LibraryElementImpl(analysisContext.getContextFor(librarySource), libraryNameNode); libraryElement.setDefiningCompilationUnit(definingCompilationUnitElement); if (entryPoint != null) { libraryElement.setEntryPoint(entryPoint); } int sourcedUnitCount = sourcedCompilationUnits.size(); libraryElement.setParts( sourcedCompilationUnits.toArray(new CompilationUnitElementImpl[sourcedUnitCount])); for (Directive directive : directivesToResolve) { directive.setElement(libraryElement); } library.setLibraryElement(libraryElement); if (sourcedUnitCount > 0) { patchTopLevelAccessors(libraryElement); } return libraryElement; }