@Test
  public void shouldConfigureProjectsWithCircularDependencies() throws CoreException, IOException {
    // the bug appeared when at least 3 projects were involved: the first project depends on the
    // second one which has a circular dependency
    // towards the second one
    Properties sonarProperties = new Properties();
    // mock three projects that depend on each other
    final String project1Name = "project1";
    final String project2Name = "project2";
    final String project3Name = "project3";
    IJavaProject project1 = mock(IJavaProject.class, Mockito.RETURNS_DEEP_STUBS);
    IJavaProject project2 = mock(IJavaProject.class, Mockito.RETURNS_DEEP_STUBS);
    IJavaProject project3 = mock(IJavaProject.class, Mockito.RETURNS_DEEP_STUBS);
    // these are required during the call to configureJavaProject
    when(project1.getOption(JavaCore.COMPILER_SOURCE, true)).thenReturn("1.6");
    when(project1.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true)).thenReturn("1.6");
    when(project1.getProject().getName()).thenReturn(project1Name);
    when(project2.getProject().getName()).thenReturn(project2Name);
    when(project3.getProject().getName()).thenReturn(project3Name);

    // create three classpathEntries, one for each Project
    IClasspathEntry entryProject1 = mock(IClasspathEntry.class, Mockito.RETURNS_DEEP_STUBS);
    IClasspathEntry entryProject2 = mock(IClasspathEntry.class, Mockito.RETURNS_DEEP_STUBS);
    IClasspathEntry entryProject3 = mock(IClasspathEntry.class, Mockito.RETURNS_DEEP_STUBS);
    when(entryProject1.getEntryKind()).thenReturn(IClasspathEntry.CPE_PROJECT);
    when(entryProject1.getPath().segment(0)).thenReturn(project1Name);
    when(entryProject2.getEntryKind()).thenReturn(IClasspathEntry.CPE_PROJECT);
    when(entryProject2.getPath().segment(0)).thenReturn(project2Name);
    when(entryProject3.getEntryKind()).thenReturn(IClasspathEntry.CPE_PROJECT);
    when(entryProject3.getPath().segment(0)).thenReturn(project3Name);
    // project1 depends on project2, which depends on project3, which depends on project2
    IClasspathEntry[] classpath1 = new IClasspathEntry[] {entryProject2};
    IClasspathEntry[] classpath2 = new IClasspathEntry[] {entryProject3};
    IClasspathEntry[] classpath3 = new IClasspathEntry[] {entryProject2};
    when(project1.getResolvedClasspath(true)).thenReturn(classpath1);
    when(project2.getResolvedClasspath(true)).thenReturn(classpath2);
    when(project3.getResolvedClasspath(true)).thenReturn(classpath3);

    // mock the JavaModel
    IJavaModel javaModel = mock(IJavaModel.class);
    when(javaModel.getJavaProject(project1Name)).thenReturn(project1);
    when(javaModel.getJavaProject(project2Name)).thenReturn(project2);
    when(javaModel.getJavaProject(project3Name)).thenReturn(project3);

    when(project1.getJavaModel()).thenReturn(javaModel);
    when(project2.getJavaModel()).thenReturn(javaModel);
    when(project3.getJavaModel()).thenReturn(javaModel);

    // this call should not fail (StackOverFlowError before patch)
    configurator.configureJavaProject(project1, sonarProperties);
  }
 private IStatus validateClassFile() {
   IPackageFragmentRoot root = getPackageFragmentRoot();
   try {
     if (root.getKind() != IPackageFragmentRoot.K_BINARY)
       return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, root);
   } catch (JavaModelException e) {
     return e.getJavaModelStatus();
   }
   IJavaProject project = getJavaProject();
   return JavaConventions.validateClassFileName(
       getElementName(),
       project.getOption(JavaCore.COMPILER_SOURCE, true),
       project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
 }
 /**
  * Constructs a SearchableEnvironmentRequestor that wraps the given SearchRequestor. The requestor
  * will not accept types in the <code>unitToSkip</code>.
  */
 public SearchableEnvironmentRequestor(
     ISearchRequestor requestor,
     ICompilationUnit unitToSkip,
     IJavaProject project,
     NameLookup nameLookup) {
   this.requestor = requestor;
   this.unitToSkip = unitToSkip;
   this.project = project;
   this.nameLookup = nameLookup;
   this.checkAccessRestrictions =
       !JavaCore.IGNORE.equals(project.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
           || !JavaCore.IGNORE.equals(
               project.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true));
 }
  public static void getUnusedAndUndocumentedParameterOrExceptionProposals(
      IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
    ICompilationUnit cu = context.getCompilationUnit();
    IJavaProject project = cu.getJavaProject();

    if (!JavaCore.ENABLED.equals(project.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, true))) {
      return;
    }

    int problemId = problem.getProblemId();
    boolean isUnusedTypeParam = problemId == IProblem.UnusedTypeParameter;
    boolean isUnusedParam = problemId == IProblem.ArgumentIsNeverUsed || isUnusedTypeParam;
    String key =
        isUnusedParam
            ? JavaCore.COMPILER_PB_UNUSED_PARAMETER_INCLUDE_DOC_COMMENT_REFERENCE
            : JavaCore.COMPILER_PB_UNUSED_DECLARED_THROWN_EXCEPTION_INCLUDE_DOC_COMMENT_REFERENCE;

    if (!JavaCore.ENABLED.equals(project.getOption(key, true))) {
      return;
    }

    ASTNode node = problem.getCoveringNode(context.getASTRoot());
    if (node == null) {
      return;
    }

    BodyDeclaration bodyDecl = ASTResolving.findParentBodyDeclaration(node);
    if (bodyDecl == null || ASTResolving.getParentMethodOrTypeBinding(bodyDecl) == null) {
      return;
    }

    String label;
    if (isUnusedTypeParam) {
      label = CorrectionMessages.JavadocTagsSubProcessor_document_type_parameter_description;
    } else if (isUnusedParam) {
      label = CorrectionMessages.JavadocTagsSubProcessor_document_parameter_description;
    } else {
      node = ASTNodes.getNormalizedNode(node);
      label = CorrectionMessages.JavadocTagsSubProcessor_document_exception_description;
    }
    ASTRewriteCorrectionProposal proposal =
        new AddMissingJavadocTagProposal(
            label,
            context.getCompilationUnit(),
            bodyDecl,
            node,
            IProposalRelevance.DOCUMENT_UNUSED_ITEM);
    proposals.add(proposal);
  }
  public void testExtractionOfCompilerSettingsDespiteErrorsInExecutionPlan() throws Exception {
    IProject[] projects =
        importProjects(
            "projects/compilerSettingsPluginError",
            new String[] {"pom.xml"},
            new ResolverConfiguration());
    assertNotNull(projects);
    assertEquals(1, projects.length);
    IProject project = projects[0];
    assertNotNull(project);

    IJavaProject javaProject = JavaCore.create(project);
    assertEquals("1.6", javaProject.getOption(JavaCore.COMPILER_SOURCE, true));
    assertEquals("1.5", javaProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
  }
  /** Test custom encoding */
  public void test02() throws CoreException {
    try {
      IJavaProject projectA =
          this.createJavaProject(
              "A",
              new String[] {}, // source folders
              new String[] {}, // lib folders
              new String[] {}, // projects
              "");
      IJavaProject projectB =
          this.createJavaProject(
              "B",
              new String[] {}, // source folders
              new String[] {}, // lib folders
              new String[] {}, // projects
              "");

      String globalEncoding = JavaCore.getOption(JavaCore.CORE_ENCODING);

      Hashtable options = new Hashtable();
      options.put(JavaCore.CORE_ENCODING, "custom");
      projectA.setOptions(options);

      // check project A custom options
      assertEquals(
          "projA:unexpected custom encoding",
          "custom",
          projectA.getOption(JavaCore.CORE_ENCODING, true));

      // check project B custom options	(should be none, indicating it sees global ones only)
      assertEquals(
          "projB:unexpected custom encoding",
          globalEncoding,
          projectB.getOption(JavaCore.CORE_ENCODING, true));

      // flush custom options - project A should revert to global ones
      projectA.setOptions(null);
      assertEquals(
          "projA:unexpected reverted encoding",
          globalEncoding,
          projectA.getOption(JavaCore.CORE_ENCODING, true));

    } finally {
      this.deleteProject("A");
      this.deleteProject("B");
    }
  }
  @Test
  public void shouldConfigureJavaSourceAndTarget() throws JavaModelException, IOException {
    IJavaProject project = mock(IJavaProject.class);
    Properties sonarProperties = new Properties();

    when(project.getOption(JavaCore.COMPILER_SOURCE, true)).thenReturn("1.6");
    when(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true)).thenReturn("1.6");
    when(project.getResolvedClasspath(true)).thenReturn(new IClasspathEntry[] {});
    when(project.getOutputLocation())
        .thenReturn(new Path(temp.newFolder("output").getAbsolutePath()));

    configurator.configureJavaProject(project, sonarProperties);

    assertTrue(sonarProperties.containsKey("sonar.java.source"));
    assertThat(sonarProperties.getProperty("sonar.java.source"), is("1.6"));
    assertTrue(sonarProperties.containsKey("sonar.java.target"));
    assertThat(sonarProperties.getProperty("sonar.java.target"), is("1.6"));
  }
 private boolean isJavadocProcessingEnabled() {
   IJavaProject project = fCompilationUnit.getJavaProject();
   boolean processJavadoc;
   if (project == null)
     processJavadoc =
         JavaCore.ENABLED.equals(JavaCore.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT));
   else
     processJavadoc =
         JavaCore.ENABLED.equals(project.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, true));
   return processJavadoc;
 }
  @Test
  public void shouldConfigureSimpleProject() throws JavaModelException, IOException {
    IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
    File workspaceRoot = root.getFullPath().toFile();
    File projectRoot = new File(workspaceRoot, "myProject");
    projectRoot.mkdir();
    File sourceFolder = new File(projectRoot, "src");
    sourceFolder.mkdir();
    File testFolder = new File(projectRoot, "test");
    testFolder.mkdir();
    File outputFolder = new File(projectRoot, "bin");
    outputFolder.mkdir();

    IJavaProject project = mock(IJavaProject.class);
    Properties sonarProperties = new Properties();

    when(project.getOption(JavaCore.COMPILER_SOURCE, true)).thenReturn("1.6");
    when(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true)).thenReturn("1.6");
    when(project.getPath()).thenReturn(new Path(projectRoot.getAbsolutePath()));

    IClasspathEntry[] cpes =
        new IClasspathEntry[] {
          createCPE(IClasspathEntry.CPE_SOURCE, sourceFolder),
          createCPE(IClasspathEntry.CPE_SOURCE, testFolder)
        };

    when(project.getResolvedClasspath(true)).thenReturn(cpes);
    when(project.getOutputLocation()).thenReturn(new Path(outputFolder.getAbsolutePath()));

    configurator.configureJavaProject(project, sonarProperties);

    // TODO Find a way to mock a project inside Eclipse

    // assertTrue(sonarProperties.containsKey("sonar.sources"));
    // assertThat(sonarProperties.getProperty("sonar.sources"), is(sourceFolder.getPath()));
    // assertTrue(sonarProperties.containsKey("sonar.tests"));
    // assertThat(sonarProperties.getProperty("sonar.tests"), is(testFolder.getPath()));
    // assertTrue(sonarProperties.containsKey("sonar.binaries"));
    // assertThat(sonarProperties.getProperty("sonar.binaries"), is(outputFolder.getPath()));
  }
  /*
   * @see SourceViewerConfiguration#getIndentPrefixes(ISourceViewer, String)
   */
  public String[] getIndentPrefixes(ISourceViewer sourceViewer, String contentType) {
    IJavaProject project = getProject();
    final int tabWidth = CodeFormatterUtil.getTabWidth(project);
    final int indentWidth = CodeFormatterUtil.getIndentWidth(project);
    boolean allowTabs = tabWidth <= indentWidth;

    String indentMode;
    if (project == null)
      indentMode = JavaCore.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR);
    else indentMode = project.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, true);

    boolean useSpaces =
        JavaCore.SPACE.equals(indentMode) || DefaultCodeFormatterConstants.MIXED.equals(indentMode);

    Assert.isLegal(allowTabs || useSpaces);

    if (!allowTabs) {
      char[] spaces = new char[indentWidth];
      Arrays.fill(spaces, ' ');
      return new String[] {new String(spaces), ""}; // $NON-NLS-1$
    } else if (!useSpaces) return getIndentPrefixesForTab(tabWidth);
    else return getIndentPrefixesForSpaces(tabWidth);
  }
  public boolean matches(IJavaProject javaProject) {
    if (fStatus != null) {
      return fStatus.booleanValue();
    }

    IConfigurationElement[] children =
        fConfigurationElement.getChildren(ExpressionTagNames.ENABLEMENT);
    if (children.length == 1) {
      try {
        ExpressionConverter parser = ExpressionConverter.getDefault();
        Expression expression = parser.perform(children[0]);
        EvaluationContext evalContext = new EvaluationContext(null, javaProject);
        evalContext.addVariable("project", javaProject); // $NON-NLS-1$
        evalContext.addVariable(
            "sourceLevel", javaProject.getOption(JavaCore.COMPILER_SOURCE, true)); // $NON-NLS-1$
        return expression.evaluate(evalContext) == EvaluationResult.TRUE;
      } catch (CoreException e) {
        JavaPlugin.log(e);
      }
      return false;
    }
    fStatus = Boolean.FALSE;
    return false;
  }
 protected final String getCoreOption(IJavaProject project, String key) {
   if (project == null) return JavaCore.getOption(key);
   return project.getOption(key, true);
 }
  /** Empty custom option must not be ignored http://bugs.eclipse.org/bugs/show_bug.cgi?id=26251 */
  public void test08() throws CoreException {
    try {
      IJavaProject projectA =
          this.createJavaProject(
              "A",
              new String[] {}, // source folders
              new String[] {}, // lib folders
              new String[] {}, // projects
              "");

      Hashtable options = new Hashtable();
      options.put(JavaCore.COMPILER_TASK_TAGS, "TODO:");
      JavaCore.setOptions(options);

      // check project A custom options
      assertEquals(
          "1#projA:unexpected custom value for task tags option",
          null,
          projectA.getOption(JavaCore.COMPILER_TASK_TAGS, false));
      assertEquals(
          "1#projA:unexpected custom value for inherited task tags option",
          "TODO:",
          projectA.getOption(JavaCore.COMPILER_TASK_TAGS, true));
      assertEquals(
          "1#workspace:unexpected custom value for task tags option",
          "TODO:",
          JavaCore.getOption(JavaCore.COMPILER_TASK_TAGS));

      // change custom options to have one less
      options.clear();
      options.put(JavaCore.COMPILER_TASK_TAGS, "");
      projectA.setOptions(options);
      assertEquals(
          "2#projA:unexpected custom value for task tags option",
          "",
          projectA.getOption(JavaCore.COMPILER_TASK_TAGS, false));
      assertEquals(
          "2#projA:unexpected custom value for inherited task tags option",
          "",
          projectA.getOption(JavaCore.COMPILER_TASK_TAGS, true));
      assertEquals(
          "2#workspace:unexpected custom value for task tags option",
          "TODO:",
          JavaCore.getOption(JavaCore.COMPILER_TASK_TAGS));

      // change custom options to have one less
      options.clear();
      options.put(JavaCore.COMPILER_TASK_TAGS, "@TODO");
      JavaCore.setOptions(options);
      assertEquals(
          "3#projA:unexpected custom value for task tags option",
          "",
          projectA.getOption(JavaCore.COMPILER_TASK_TAGS, false));
      assertEquals(
          "3#projA:unexpected custom value for inherited task tags option",
          "",
          projectA.getOption(JavaCore.COMPILER_TASK_TAGS, true));
      assertEquals(
          "3#workspace:unexpected custom value for task tags option",
          "@TODO",
          JavaCore.getOption(JavaCore.COMPILER_TASK_TAGS));

    } finally {
      this.deleteProject("A");
    }
  }
 /**
  * Returns the possibly <code>project</code>-specific core preference defined under <code>key
  * </code>.
  *
  * @param project the project to get the preference from, or <code>null</code> to get the global
  *     preference
  * @param key the key of the preference
  * @return the value of the preference
  * @since 3.5
  */
 private static String getCoreOption(IJavaProject project, String key) {
   if (project == null) return JavaCore.getOption(key);
   return project.getOption(key, true);
 }
  /** @exception JavaModelException if setting the source of the original compilation unit fails */
  protected void executeOperation() throws JavaModelException {
    try {
      beginTask(Messages.workingCopy_commit, 2);
      CompilationUnit workingCopy = getCompilationUnit();

      if (ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(
          workingCopy.getJavaProject().getElementName())) {
        // case of a working copy without a resource
        workingCopy.getBuffer().save(this.progressMonitor, this.force);
        return;
      }

      ICompilationUnit primary = workingCopy.getPrimary();
      boolean isPrimary = workingCopy.isPrimary();

      JavaElementDeltaBuilder deltaBuilder = null;
      PackageFragmentRoot root =
          (PackageFragmentRoot) workingCopy.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
      boolean isIncluded = !Util.isExcluded(workingCopy);
      IFile resource = (IFile) workingCopy.getResource();
      IJavaProject project = root.getJavaProject();
      if (isPrimary
          || (root.validateOnClasspath().isOK()
              && isIncluded
              && resource.isAccessible()
              && Util.isValidCompilationUnitName(
                  workingCopy.getElementName(),
                  project.getOption(JavaCore.COMPILER_SOURCE, true),
                  project.getOption(JavaCore.COMPILER_COMPLIANCE, true)))) {

        // force opening so that the delta builder can get the old info
        if (!isPrimary && !primary.isOpen()) {
          primary.open(null);
        }

        // creates the delta builder (this remembers the content of the cu) if:
        // - it is not excluded
        // - and it is not a primary or it is a non-consistent primary
        if (isIncluded && (!isPrimary || !workingCopy.isConsistent())) {
          deltaBuilder = new JavaElementDeltaBuilder(primary);
        }

        // save the cu
        IBuffer primaryBuffer = primary.getBuffer();
        if (!isPrimary) {
          if (primaryBuffer == null) return;
          char[] primaryContents = primaryBuffer.getCharacters();
          boolean hasSaved = false;
          try {
            IBuffer workingCopyBuffer = workingCopy.getBuffer();
            if (workingCopyBuffer == null) return;
            primaryBuffer.setContents(workingCopyBuffer.getCharacters());
            primaryBuffer.save(this.progressMonitor, this.force);
            primary.makeConsistent(this);
            hasSaved = true;
          } finally {
            if (!hasSaved) {
              // restore original buffer contents since something went wrong
              primaryBuffer.setContents(primaryContents);
            }
          }
        } else {
          // for a primary working copy no need to set the content of the buffer again
          primaryBuffer.save(this.progressMonitor, this.force);
          primary.makeConsistent(this);
        }
      } else {
        // working copy on cu outside classpath OR resource doesn't exist yet
        String encoding = null;
        try {
          encoding = resource.getCharset();
        } catch (CoreException ce) {
          // use no encoding
        }
        String contents = workingCopy.getSource();
        if (contents == null) return;
        try {
          byte[] bytes = encoding == null ? contents.getBytes() : contents.getBytes(encoding);
          ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
          if (resource.exists()) {
            resource.setContents(
                stream,
                this.force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
                null);
          } else {
            resource.create(stream, this.force, this.progressMonitor);
          }
        } catch (CoreException e) {
          throw new JavaModelException(e);
        } catch (UnsupportedEncodingException e) {
          throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
        }
      }

      setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);

      // make sure working copy is in sync
      workingCopy.updateTimeStamp((CompilationUnit) primary);
      workingCopy.makeConsistent(this);
      worked(1);

      // build the deltas
      if (deltaBuilder != null) {
        deltaBuilder.buildDeltas();

        // add the deltas to the list of deltas created during this operation
        if (deltaBuilder.delta != null) {
          addDelta(deltaBuilder.delta);
        }
      }
      worked(1);
    } finally {
      done();
    }
  }
  /**
   * Finds the key defined by the given match. The assumption is that the key is the only argument
   * and it is a string literal i.e. quoted ("...") or a string constant i.e. 'static final String'
   * defined in the same class.
   *
   * @param keyPositionResult reference parameter: will be filled with the position of the found key
   * @param enclosingElement enclosing java element
   * @return a string denoting the key, {@link #NO_KEY} if no key can be found and <code>null</code>
   *     otherwise
   * @throws CoreException if a problem occurs while accessing the <code>enclosingElement</code>
   */
  private String findKey(Position keyPositionResult, IJavaElement enclosingElement)
      throws CoreException {
    ICompilationUnit unit =
        (ICompilationUnit) enclosingElement.getAncestor(IJavaElement.COMPILATION_UNIT);
    if (unit == null) return null;

    String source = unit.getSource();
    if (source == null) return null;

    IJavaProject javaProject = unit.getJavaProject();
    IScanner scanner = null;
    if (javaProject != null) {
      String complianceLevel = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
      String sourceLevel = javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
      scanner = ToolFactory.createScanner(false, false, false, sourceLevel, complianceLevel);
    } else {
      scanner = ToolFactory.createScanner(false, false, false, false);
    }
    scanner.setSource(source.toCharArray());
    scanner.resetTo(keyPositionResult.getOffset() + keyPositionResult.getLength(), source.length());

    try {
      if (scanner.getNextToken() != ITerminalSymbols.TokenNameDOT) return null;

      if (scanner.getNextToken() != ITerminalSymbols.TokenNameIdentifier) return null;

      String src = new String(scanner.getCurrentTokenSource());
      int tokenStart = scanner.getCurrentTokenStartPosition();
      int tokenEnd = scanner.getCurrentTokenEndPosition();

      if (scanner.getNextToken() == ITerminalSymbols.TokenNameLPAREN) {
        // Old school
        // next must be key string. Ignore methods which do not take a single String parameter (Bug
        // 295040).
        int nextToken = scanner.getNextToken();
        if (nextToken != ITerminalSymbols.TokenNameStringLiteral
            && nextToken != ITerminalSymbols.TokenNameIdentifier) return null;

        tokenStart = scanner.getCurrentTokenStartPosition();
        tokenEnd = scanner.getCurrentTokenEndPosition();
        int token;
        while ((token = scanner.getNextToken()) == ITerminalSymbols.TokenNameDOT) {
          if ((nextToken = scanner.getNextToken()) != ITerminalSymbols.TokenNameIdentifier) {
            return null;
          }
          tokenStart = scanner.getCurrentTokenStartPosition();
          tokenEnd = scanner.getCurrentTokenEndPosition();
        }
        if (token != ITerminalSymbols.TokenNameRPAREN) return null;

        if (nextToken == ITerminalSymbols.TokenNameStringLiteral) {
          keyPositionResult.setOffset(tokenStart + 1);
          keyPositionResult.setLength(tokenEnd - tokenStart - 1);
          return source.substring(tokenStart + 1, tokenEnd);
        } else if (nextToken == ITerminalSymbols.TokenNameIdentifier) {
          keyPositionResult.setOffset(tokenStart);
          keyPositionResult.setLength(tokenEnd - tokenStart + 1);
          IType parentClass = (IType) enclosingElement.getAncestor(IJavaElement.TYPE);
          IField[] fields = parentClass.getFields();
          String identifier = source.substring(tokenStart, tokenEnd + 1);
          for (int i = 0; i < fields.length; i++) {
            if (fields[i].getElementName().equals(identifier)) {
              if (!Signature.getSignatureSimpleName(fields[i].getTypeSignature())
                  .equals("String")) // $NON-NLS-1$
              return null;
              Object obj = fields[i].getConstant();
              return obj instanceof String
                  ? ((String) obj).substring(1, ((String) obj).length() - 1)
                  : NO_KEY;
            }
          }
        }
        return NO_KEY;
      } else {
        keyPositionResult.setOffset(tokenStart);
        keyPositionResult.setLength(tokenEnd - tokenStart + 1);
        return src;
      }
    } catch (InvalidInputException e) {
      throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e));
    }
  }
  /** Test persistence of project custom options */
  public void test01() throws CoreException {
    try {
      IJavaProject projectA =
          this.createJavaProject(
              "A",
              new String[] {}, // source folders
              new String[] {}, // lib folders
              new String[] {}, // projects
              "");
      IJavaProject projectB =
          this.createJavaProject(
              "B",
              new String[] {}, // source folders
              new String[] {}, // lib folders
              new String[] {}, // projects
              "");

      Hashtable options = new Hashtable();
      options.put(JavaCore.COMPILER_PB_DEPRECATION_IN_DEPRECATED_CODE, JavaCore.DISABLED);
      options.put(JavaCore.COMPILER_COMPLIANCE, "8.0");
      options.put(JavaCore.COMPILER_PB_HIDDEN_CATCH_BLOCK, JavaCore.ERROR);
      JavaCore.setOptions(options);

      options.clear();
      options.put(JavaCore.COMPILER_PB_DEPRECATION_IN_DEPRECATED_CODE, JavaCore.ENABLED);
      options.put(JavaCore.COMPILER_COMPLIANCE, "10.0");
      projectA.setOptions(options);

      // check project A custom options
      assertEquals(
          "projA:unexpected custom value for deprecation option",
          JavaCore.ENABLED,
          projectA.getOption(JavaCore.COMPILER_PB_DEPRECATION_IN_DEPRECATED_CODE, true));
      assertEquals(
          "projA:unexpected custom value for compliance option",
          "10.0",
          projectA.getOption(JavaCore.COMPILER_COMPLIANCE, true));
      assertEquals(
          "projA:unexpected inherited value1 for hidden-catch option",
          JavaCore.ERROR,
          projectA.getOption(JavaCore.COMPILER_PB_HIDDEN_CATCH_BLOCK, true));

      // check project B custom options	(should be none, indicating it sees global ones only)
      assertEquals(
          "projB:unexpected custom value for deprecation option",
          JavaCore.DISABLED,
          projectB.getOption(JavaCore.COMPILER_PB_DEPRECATION_IN_DEPRECATED_CODE, true));
      assertEquals(
          "projB:unexpected custom value for compliance option",
          "8.0",
          projectB.getOption(JavaCore.COMPILER_COMPLIANCE, true));
      assertEquals(
          "projB:unexpected inherited value for hidden-catch option",
          JavaCore.ERROR,
          projectB.getOption(JavaCore.COMPILER_PB_HIDDEN_CATCH_BLOCK, true));

      // flush custom options - project A should revert to global ones
      projectA.setOptions(null);
      assertEquals(
          "projA:unexpected reverted value for deprecation option",
          JavaCore.DISABLED,
          projectA.getOption(JavaCore.COMPILER_PB_DEPRECATION_IN_DEPRECATED_CODE, true));
      assertEquals(
          "projA:unexpected reverted value for compliance option",
          "8.0",
          projectA.getOption(JavaCore.COMPILER_COMPLIANCE, true));
      assertEquals(
          "projA:unexpected inherited value2 for hidden-catch option",
          JavaCore.ERROR,
          projectA.getOption(JavaCore.COMPILER_PB_HIDDEN_CATCH_BLOCK, true));

    } finally {
      this.deleteProject("A");
      this.deleteProject("B");
    }
  }
  /**
   * Get the options that are presented to annotation processors by the
   * AnnotationProcessorEnvironment. Options are key/value pairs which are set in the project
   * properties.
   *
   * <p>Option values can begin with a percent-delimited token representing a classpath variable or
   * one of several predefined values. The token must either be followed by a path delimiter, or be
   * the entire value. Such tokens will be replaced with their resolved value. The predefined values
   * are <code>%ROOT%</code>, which is replaced by the absolute pathname of the workspace root
   * directory, and <code>%PROJECT.DIR%</code>, which will be replaced by the absolute pathname of
   * the project root directory. For example, a value of <code>
   * %ECLIPSE_HOME%/configuration/config.ini</code> might be resolved to <code>
   * d:/eclipse/configuration/config.ini</code>.
   *
   * <p>This method returns some options which are set programmatically but are not directly
   * editable, are not displayed in the configuration GUI, and are not persisted to the preference
   * store. This is meant to emulate the behavior of Sun's apt command-line tool, which passes most
   * of its command line options to the processor environment. The programmatically set options are:
   * <code>-classpath</code> [set to Java build path] <code>-sourcepath</code> [set to Java source
   * path] <code>-s</code> [set to generated src dir] <code>-d</code> [set to binary output dir]
   * <code>-target</code> [set to compiler target version] <code>-source</code> [set to compiler
   * source version]
   *
   * <p>There are some slight differences between the options returned by this method and the
   * options returned from this implementation of @see AnnotationProcessorEnvironment#getOptions().
   * First, that method returns additional options which are only meaningful during a build, such as
   * <code>phase</code>. Second, that method also adds alternate encodings of each option, to be
   * compatible with a bug in Sun's apt implementation: specifically, for each option key="k",
   * value="v", an additional option is created with key="-Ak=v", value=null. This includes the
   * user-created options, but does not include the programmatically defined options listed above.
   *
   * @param jproj a project, or null to query the workspace-wide setting.
   * @return a mutable, possibly empty, map of (key, value) pairs. The value part of a pair may be
   *     null (equivalent to "-Akey" on the Sun apt command line). The value part may contain
   *     spaces.
   */
  public static Map<String, String> getProcessorOptions(IJavaProject jproj) {
    Map<String, String> rawOptions = getRawProcessorOptions(jproj);
    // map is large enough to also include the programmatically generated options
    Map<String, String> options = new HashMap<String, String>(rawOptions.size() + 6);

    // Resolve path metavariables like %ROOT%
    for (Map.Entry<String, String> entry : rawOptions.entrySet()) {
      String resolvedValue = resolveVarPath(jproj, entry.getValue());
      String value = (resolvedValue == null) ? entry.getValue() : resolvedValue;
      options.put(entry.getKey(), value);
    }

    if (jproj == null) {
      // there are no programmatically set options at the workspace level
      return options;
    }

    IWorkspaceRoot root = jproj.getProject().getWorkspace().getRoot();

    // Add sourcepath and classpath variables
    try {
      IClasspathEntry[] classpathEntries = jproj.getResolvedClasspath(true);
      Set<String> classpath = new LinkedHashSet<String>();
      Set<String> sourcepath = new LinkedHashSet<String>();

      // For projects on the classpath, loops can exist; need to make sure we
      // don't loop forever
      Set<IJavaProject> projectsProcessed = new HashSet<IJavaProject>();
      projectsProcessed.add(jproj);
      for (IClasspathEntry entry : classpathEntries) {
        int kind = entry.getEntryKind();
        if (kind == IClasspathEntry.CPE_LIBRARY) {
          IPath cpPath = entry.getPath();

          IResource res = root.findMember(cpPath);

          // If res is null, the path is absolute (it's an external jar)
          if (res == null) {
            classpath.add(cpPath.toOSString());
          } else {
            // It's relative
            classpath.add(res.getLocation().toOSString());
          }
        } else if (kind == IClasspathEntry.CPE_SOURCE) {
          IResource res = root.findMember(entry.getPath());
          if (res == null) {
            continue;
          }
          IPath srcPath = res.getLocation();
          if (srcPath == null) {
            continue;
          }

          sourcepath.add(srcPath.toOSString());
        } else if (kind == IClasspathEntry.CPE_PROJECT) {
          // Add the dependent project's build path and classpath to ours
          IPath otherProjectPath = entry.getPath();
          IProject otherProject = root.getProject(otherProjectPath.segment(0));

          // Note: JavaCore.create() is safe, even if the project is null --
          // in that case, we get null back
          IJavaProject otherJavaProject = JavaCore.create(otherProject);

          // If it doesn't exist, ignore it
          if (otherJavaProject != null && otherJavaProject.isOpen()) {
            addProjectClasspath(root, otherJavaProject, projectsProcessed, classpath);
          }
        }
      }
      // if you add options here, also add them in isAutomaticProcessorOption(),
      // and document them in docs/reference/automatic_processor_options.html.

      // Classpath and sourcepath
      options.put("-classpath", convertPathCollectionToString(classpath)); // $NON-NLS-1$    	
      options.put("-sourcepath", convertPathCollectionToString(sourcepath)); // $NON-NLS-1$

      // Get absolute path for generated source dir
      IFolder genSrcDir = jproj.getProject().getFolder(getGenSrcDir(jproj));
      String genSrcDirString = genSrcDir.getRawLocation().toOSString();
      options.put("-s", genSrcDirString); // $NON-NLS-1$

      // Absolute path for bin dir as well
      IPath binPath = jproj.getOutputLocation();
      IResource binPathResource = root.findMember(binPath);
      String binDirString;
      if (binPathResource != null) {
        binDirString = root.findMember(binPath).getLocation().toOSString();
      } else {
        binDirString = binPath.toOSString();
      }
      options.put("-d", binDirString); // $NON-NLS-1$

      String target = jproj.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true);
      options.put("-target", target); // $NON-NLS-1$

      String source = jproj.getOption(JavaCore.COMPILER_SOURCE, true);
      options.put("-source", source); // $NON-NLS-1$
    } catch (JavaModelException jme) {
      AptPlugin.log(jme, "Could not get the classpath for project: " + jproj); // $NON-NLS-1$
    }

    return options;
  }