com.intellij.psi.util.PsiTreeUtil Java Examples

The following examples show how to use com.intellij.psi.util.PsiTreeUtil. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source Project: consulo   Author: consulo   File: Identikit.java    License: Apache License 2.0 6 votes vote down vote up
public PsiElement findInside(@Nonnull PsiElement element, int startOffset, int endOffset) {
  PsiElement anchor = AbstractFileViewProvider.findElementAt(element, startOffset); // finds child in this tree only, unlike PsiElement.findElementAt()
  if (anchor == null && startOffset == element.getTextLength()) {
    anchor = PsiTreeUtil.getDeepestLast(element);
  }
  if (anchor == null) return null;

  PsiElement result = findParent(startOffset, endOffset, anchor);
  if (endOffset == startOffset) {
    while ((result == null || result.getTextRange().getStartOffset() != startOffset) && anchor.getTextRange().getStartOffset() == endOffset) {
      anchor = PsiTreeUtil.prevLeaf(anchor, false);
      if (anchor == null) break;

      result = findParent(startOffset, endOffset, anchor);
    }
  }
  return result;

}
 
Example #2
Source Project: IntelliJDeodorant   Author: JetBrains-Research   File: MethodObject.java    License: MIT License 6 votes vote down vote up
public boolean containsFieldAccessOfEnclosingClass() {
    //check for field access like SegmentedTimeline.this.segmentsIncluded
    if (getPsiMethod().getBody() == null) {
        return false;
    }

    ExpressionExtractor expressionExtractor = new ExpressionExtractor();
    List<PsiExpression> fieldAccesses = expressionExtractor.getVariableInstructions(getPsiMethod().getBody().getStatements());
    for (PsiExpression expression : fieldAccesses) {
        PsiReferenceExpression fieldReference = (PsiReferenceExpression) expression;
        Collection<PsiElement> psiElements = PsiTreeUtil.findChildrenOfType(fieldReference, PsiThisExpression.class);

        for (PsiElement thisExpressionElement : psiElements) {
            PsiThisExpression thisExpression = (PsiThisExpression) thisExpressionElement;
            if (thisExpression.getQualifier() != null) {
                return true;
            }
        }
    }
    return false;
}
 
Example #3
Source Project: intellij-haskforce   Author: carymrobbins   File: HaskellUtil.java    License: Apache License 2.0 6 votes vote down vote up
/**
 * Find definitions that have been re-exported.
 *
 * <code>
 *   module Foo (module Bar, foo) where
 *   import Bar
 *   import Baz (foo)
 * </code>
 */
private static void findDefinitionNodeInExport(@NotNull Project project, HaskellFile f, @Nullable String name,
                                               @Nullable PsiNamedElement e, List<PsiNamedElement> result) {
    List<HaskellPsiUtil.Import> imports = HaskellPsiUtil.parseImports(f);
    for (HaskellExport export : PsiTreeUtil.findChildrenOfType(f, HaskellExport.class)) {
        boolean exportFn = export.getQvar() != null && export.getQvar().getQvarid() != null
                && export.getQvar().getQvarid().getVarid().getName().equals(name);
        String moduleName = exportFn
                ? getModule(export.getQvar().getQvarid().getConidList())
                : export.getModuletoken() != null && export.getQconid() != null ? export.getQconid().getText() : null;
        if (!exportFn && moduleName == null) continue;
        for (HaskellPsiUtil.Import imprt : imports) {
            if (moduleName != null && !moduleName.equals(imprt.module) && !moduleName.equals(imprt.alias)) continue;
            boolean hidden = imprt.getHidingNames() != null && ArrayUtil.contains(name, imprt.getHidingNames());
            boolean notImported = imprt.getImportedNames() != null && !ArrayUtil.contains(name, imprt.getImportedNames());
            if (hidden || notImported) continue;
            for (HaskellFile f2 : HaskellModuleIndex.getFilesByModuleName(project, imprt.module, GlobalSearchScope.allScope(project))) {
                findDefinitionNode(f2, name, e, result);
                findDefinitionNodeInExport(project, f2, name, e, result);
            }
        }
    }
}
 
Example #4
@Override
public void actionPerformedImpl(@NotNull final Project project, final Editor editor) {
    PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);
    if(file == null) {
        return;
    }

    int offset = editor.getCaretModel().getOffset();
    PsiElement psiElement = file.findElementAt(offset);
    if(psiElement == null) {
        return;
    }

    PsiLocalVariable psiLocalVariable = PsiTreeUtil.getParentOfType(psiElement, PsiLocalVariable.class);
    InflateViewAnnotator.InflateContainer inflateContainer = InflateViewAnnotator.matchInflate(psiLocalVariable);
    if(inflateContainer == null) {
        return;
    }

    generate(inflateContainer, editor, file);
}
 
Example #5
Source Project: BashSupport   Author: BashSupport   File: BashPsiUtils.java    License: Apache License 2.0 6 votes vote down vote up
/**
 * This tree walkup method does continue even if a valid definition has been found on an more-inner level.
 * Bash is different in regard to the definitions, the most outer definitions count, not the most inner / the first one found.
 *
 * @param processor
 * @param entrance
 * @param maxScope
 * @param state
 * @return
 */
public static boolean varResolveTreeWalkUp(@NotNull final PsiScopeProcessor processor,
                                           @NotNull final BashVar entrance,
                                           @Nullable final PsiElement maxScope,
                                           @NotNull final ResolveState state) {
    PsiElement prevParent = entrance;
    PsiElement scope = entrance;

    boolean hasResult = false;

    while (scope != null) {
        hasResult |= !scope.processDeclarations(processor, state, prevParent, entrance);

        if (scope == maxScope) {
            break;
        }

        prevParent = scope;
        scope = PsiTreeUtil.getStubOrPsiParent(prevParent);
    }

    return !hasResult;
}
 
Example #6
Source Project: buck   Author: facebook   File: BuckGotoProvider.java    License: Apache License 2.0 6 votes vote down vote up
@Nullable
private PsiElement resolveAsLoadArgument(
    Project project, VirtualFile sourceFile, BuckLoadArgument buckLoadArgument) {
  BuckLoadCall buckLoadCall = PsiTreeUtil.getParentOfType(buckLoadArgument, BuckLoadCall.class);
  if (buckLoadCall == null) {
    return null;
  }
  BuckTargetLocator buckTargetLocator = BuckTargetLocator.getInstance(project);
  return Optional.of(buckLoadCall.getLoadTargetArgument().getString())
      .map(BuckString::getValue)
      .flatMap(BuckTarget::parse)
      .flatMap(target -> buckTargetLocator.resolve(sourceFile, target))
      .flatMap(buckTargetLocator::findVirtualFileForExtensionFile)
      .map(PsiManager.getInstance(project)::findFile)
      .map(
          psiFile ->
              BuckPsiUtils.findSymbolInPsiTree(psiFile, buckLoadArgument.getString().getValue()))
      .orElse(null);
}
 
Example #7
Source Project: consulo-csharp   Author: consulo   File: CSharpLinqQueryBodyImpl.java    License: Apache License 2.0 6 votes vote down vote up
@Override
public boolean processDeclarations(@Nonnull PsiScopeProcessor processor,
		@Nonnull ResolveState state,
		PsiElement lastParent,
		@Nonnull PsiElement place)
{
	if(lastParent == null || !PsiTreeUtil.isAncestor(this, lastParent, false))
	{
		return true;
	}

	for(PsiElement psiElement : getChildren())
	{
		if(!psiElement.processDeclarations(processor, state, lastParent, place))
		{
			return false;
		}
	}
	return super.processDeclarations(processor, state, lastParent, place);
}
 
Example #8
Source Project: consulo-csharp   Author: consulo   File: ThisKindProcessor.java    License: Apache License 2.0 6 votes vote down vote up
@RequiredReadAction
@Override
public void process(@Nonnull CSharpResolveOptions options,
		@Nonnull DotNetGenericExtractor defaultExtractor,
		@Nullable PsiElement forceQualifierElement,
		@Nonnull Processor<ResolveResult> processor)
{
	DotNetTypeDeclaration thisTypeDeclaration = PsiTreeUtil.getContextOfType(options.getElement(), DotNetTypeDeclaration.class);
	if(thisTypeDeclaration != null)
	{
		thisTypeDeclaration = CSharpCompositeTypeDeclaration.selectCompositeOrSelfType(thisTypeDeclaration);

		DotNetGenericExtractor genericExtractor = DotNetGenericExtractor.EMPTY;
		int genericParametersCount = thisTypeDeclaration.getGenericParametersCount();
		if(genericParametersCount > 0)
		{
			Map<DotNetGenericParameter, DotNetTypeRef> map = new THashMap<>(genericParametersCount);
			for(DotNetGenericParameter genericParameter : thisTypeDeclaration.getGenericParameters())
			{
				map.put(genericParameter, new CSharpTypeRefFromGenericParameter(genericParameter));
			}
			genericExtractor = CSharpGenericExtractor.create(map);
		}
		processor.process(new CSharpResolveResultWithExtractor(thisTypeDeclaration, genericExtractor));
	}
}
 
Example #9
Source Project: litho   Author: facebook   File: ComponentShortNamesCacheTest.java    License: Apache License 2.0 6 votes vote down vote up
@Test
public void getAllClassNames() throws IOException {
  // Add file to cache
  final Project project = testHelper.getFixture().getProject();
  final PsiFile file = testHelper.configure("LayoutSpec.java");

  ApplicationManager.getApplication()
      .invokeAndWait(
          () -> {
            final ComponentShortNamesCache namesCache = new ComponentShortNamesCache(project);
            // Add file to cache
            final PsiClass cls = PsiTreeUtil.findChildOfType(file, PsiClass.class);
            ComponentsCacheService.getInstance(project).maybeUpdate(cls, false);

            final String[] allClassNames = namesCache.getAllClassNames();
            assertThat(allClassNames.length).isOne();
            assertThat(allClassNames[0]).isEqualTo("Layout");
          });
}
 
Example #10
Source Project: intellij-plugin-v4   Author: antlr   File: ImportResolver.java    License: BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
private static PsiElement resolveInImportedFiles(PsiFile grammarFile, String ruleName, List<PsiFile> visitedFiles) {
	DelegateGrammarsVisitor visitor = new DelegateGrammarsVisitor();
	grammarFile.accept(visitor);

	for ( PsiFile importedGrammar : visitor.importedGrammars ) {
		if ( visitedFiles.contains(importedGrammar) ) {
			continue;
		}
		visitedFiles.add(importedGrammar);

		GrammarSpecNode grammar = PsiTreeUtil.getChildOfType(importedGrammar, GrammarSpecNode.class);
		PsiElement specNode = MyPsiUtils.findSpecNode(grammar, ruleName);

		if ( specNode!=null ) {
			return specNode;
		}

		// maybe the imported grammar also imports other grammars itself?
		specNode = resolveInImportedFiles(importedGrammar, ruleName, visitedFiles);
		if ( specNode!=null ) {
			return specNode;
		}
	}

	return null;
}
 
Example #11
Source Project: camel-idea-plugin   Author: camel-tooling   File: XmlCamelIdeaUtils.java    License: Apache License 2.0 6 votes vote down vote up
@Override
public boolean isCamelExpressionUsedAsPredicate(PsiElement element, String language) {
    // xml
    XmlTag xml = PsiTreeUtil.getParentOfType(element, XmlTag.class);
    if (xml != null) {
        // if its coming from the log EIP then its not a predicate
        if ("simple".equals(language) && xml.getLocalName().equals("log")) {
            return false;
        }

        // special for loop which can be both expression or predicate
        if (getIdeaUtils().hasParentXmlTag(xml, "loop")) {
            XmlTag parent = PsiTreeUtil.getParentOfType(xml, XmlTag.class);
            if (parent != null) {
                String doWhile = parent.getAttributeValue("doWhile");
                return "true".equalsIgnoreCase(doWhile);
            }
        }
        return Arrays.stream(PREDICATE_EIPS).anyMatch(n -> getIdeaUtils().hasParentXmlTag(xml, n));
    }
    return false;
}
 
Example #12
Source Project: Buck-IntelliJ-Plugin   Author: wangyanxing   File: BuckGotoProvider.java    License: Apache License 2.0 6 votes vote down vote up
@Override
public PsiElement getGotoDeclarationTarget(@Nullable PsiElement source, Editor editor) {
  if (source != null && source.getLanguage() instanceof BuckLanguage) {
    // The parent type of the element must be BuckValue
    BuckValue value = PsiTreeUtil.getParentOfType(source, BuckValue.class);
    if (value == null) {
      return null;
    }
    final Project project = editor.getProject();
    if (project == null) {
      return null;
    }

    String target = source.getText();
    if (target.startsWith("'") && target.endsWith("'")) {
      target = target.substring(1, target.length() - 1);
    }
    VirtualFile targetBuckFile =
        BuckBuildUtil.getBuckFileFromAbsoluteTarget(project, target);
    if (targetBuckFile == null) {
      return null;
    }
    return PsiManager.getInstance(project).findFile(targetBuckFile);
  }
  return null;
}
 
Example #13
Source Project: idea-php-typo3-plugin   Author: cedricziel   File: UnusedActionControllerMethodInspectionSuppressor.java    License: MIT License 6 votes vote down vote up
@Override
public boolean isSuppressedFor(@NotNull PsiElement element, @NotNull String toolId) {
    if (!toolId.equals("PhpUnused")) {
        return false;
    }

    if (isActionMethod(element)) {
        PsiElement classParent = PsiTreeUtil.findFirstParent(element, e -> e instanceof PhpClass);
        if (classParent == null) {
            return false;
        }

        return isControllerPhpClass((PhpClass) classParent);
    }

    if (isControllerClassElement(element)) {
        return isControllerPhpClass((PhpClass) element);
    }

    return false;
}
 
Example #14
Source Project: CodeMaker   Author: x-hansong   File: CodeMakerUtil.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Gets all classes in the element.
 *
 * @param element the Element
 * @return the Classes
 */
public static List<PsiClass> getClasses(PsiElement element) {
    List<PsiClass> elements = Lists.newArrayList();
    List<PsiClass> classElements = PsiTreeUtil.getChildrenOfTypeAsList(element, PsiClass.class);
    elements.addAll(classElements);
    for (PsiClass classElement : classElements) {
        elements.addAll(getClasses(classElement));
    }
    return elements;
}
 
Example #15
Source Project: BashSupport   Author: BashSupport   File: BashWordImplTest.java    License: Apache License 2.0 5 votes vote down vote up
@NotNull
private BashWord configureWord(String text) {
    PsiFile file = myFixture.configureByText(BashFileType.BASH_FILE_TYPE, text);

    BashWord string = PsiTreeUtil.findChildOfType(file, BashWord.class);
    Assert.assertNotNull(string);
    return string;
}
 
Example #16
Source Project: camel-idea-plugin   Author: camel-tooling   File: BeanInjectLineMarkerProvider.java    License: Apache License 2.0 5 votes vote down vote up
private PsiAnnotation getBeanInjectAnnotation(PsiElement element) {
    if (element instanceof PsiIdentifier && element.getText().equals("BeanInject")) {
        PsiAnnotation annotation = PsiTreeUtil.getParentOfType(element, PsiAnnotation.class);
        if (annotation != null && CamelIdeaUtils.BEAN_INJECT_ANNOTATION.equals(annotation.getQualifiedName())) {
            return annotation;
        }
    }
    return null;
}
 
Example #17
Source Project: intellij-reference-diagram   Author: Stefku   File: FileFQN.java    License: Apache License 2.0 5 votes vote down vote up
public static FileFQN resolveHierarchically(PsiElement psiElement) {
    PsiJavaFile psiJavaFile = PsiTreeUtil.getParentOfType(psiElement, PsiJavaFile.class, true);
    if (psiJavaFile == null) {
        return null;
    }
    return from((PsiJavaFile) psiJavaFile);
}
 
Example #18
Source Project: reasonml-idea-plugin   Author: reasonml-editor   File: DirectiveParsingTest.java    License: MIT License 5 votes vote down vote up
public void testEndif() {
    FileBase f = parseCode("#if BS then\nx\n#else\ny\n#endif");
    PsiDirective e = PsiTreeUtil.findChildOfType(f, PsiDirective.class);

    assertNotNull(e);
    assertEquals("#if BS then\nx\n#else\ny\n#endif", e.getText());
}
 
Example #19
Source Project: intellij   Author: bazelbuild   File: Specs2Utils.java    License: Apache License 2.0 5 votes vote down vote up
@Nullable
private static ScInfixExpr getContainingInfixExpr(
    PsiElement element, Predicate<PsiElement> predicate) {
  while (element != null && !predicate.test(element)) {
    element = PsiTreeUtil.getParentOfType(element, ScInfixExpr.class);
  }
  return (ScInfixExpr) element;
}
 
Example #20
Source Project: arma-intellij-plugin   Author: kayler-renslow   File: SQFFile.java    License: MIT License 5 votes vote down vote up
/**
 * @return the only {@link SQFFileScope} instance for this file
 */
@NotNull
public SQFFileScope getFileScope() {
	SQFFileScope scope = PsiTreeUtil.findChildOfType(this, SQFFileScope.class);
	if (scope == null) {
		throw new IllegalStateException("scope shouldn't be null");
	}
	return scope;
}
 
Example #21
Source Project: reasonml-idea-plugin   Author: reasonml-editor   File: FunctorTest.java    License: MIT License 5 votes vote down vote up
public void testFunctorInstantiationChaining() {
    PsiFile file = parseCode("module KeyTable = Hashtbl.Make(KeyHash);\ntype infos;");
    List<PsiNameIdentifierOwner> expressions = new ArrayList<>(expressions(file));

    assertEquals(2, expressions.size());

    PsiInnerModule module = (PsiInnerModule) expressions.get(0);
    assertNull(module.getBody());
    PsiFunctorCall call = PsiTreeUtil.findChildOfType(module, PsiFunctorCall.class);
    assertNotNull(call);
    assertEquals("Hashtbl.Make(KeyHash)", call.getText());
}
 
Example #22
Source Project: eslint-plugin   Author: idok   File: DotNotationActionFix.java    License: MIT License 5 votes vote down vote up
@Override
public void invoke(@NotNull Project project, @NotNull PsiFile psiFile, @Nullable("is null when called from inspection") Editor editor, @NotNull PsiElement element, @NotNull PsiElement end) throws IncorrectOperationException {
    JSIndexedPropertyAccessExpression indexed = PsiTreeUtil.getParentOfType(element, JSIndexedPropertyAccessExpression.class);
    JSReferenceExpression ref = PsiTreeUtil.findChildOfType(indexed, JSReferenceExpression.class);
    JSLiteralExpression literalExpression = (JSLiteralExpression) indexed.getIndexExpression();
    String path = StringUtil.stripQuotesAroundValue(literalExpression.getText());
    ASTNode dotExp = JSChangeUtil.createStatementFromText(project, ref.getText() + '.' + path);
    indexed.replace(dotExp.getPsi());
}
 
Example #23
Source Project: reasonml-idea-plugin   Author: reasonml-editor   File: FunctionParsingTest.java    License: MIT License 5 votes vote down vote up
public void testFunctionFun() {
    PsiLet e = first(letExpressions(parseCode("let _ = fun (_, info as ei) -> x")));

    assertTrue(e.isFunction());
    PsiFunction function = e.getFunction();
    assertEquals("(_, info as ei)", PsiTreeUtil.findChildOfType(function, PsiParameters.class).getText());
    assertEquals("x", function.getBody().getText());
}
 
Example #24
Source Project: JetBrains-NASM-Language   Author: ajkhoury   File: NASMUtil.java    License: MIT License 5 votes vote down vote up
static List<NASMIdentifier> findIdentifierReferences(PsiFile containingFile, NASMIdentifier identifier) {
    List<NASMIdentifier> result = new ArrayList<>();
    PsiElement targetIdentifierId = identifier.getNameIdentifier();
    // First check the containing file's identifiers
    Collection<NASMIdentifier> nasmIdentifiers = PsiTreeUtil.collectElementsOfType(containingFile, NASMIdentifier.class);
    for (NASMIdentifier nasmIdentifier : nasmIdentifiers) {
        if (nasmIdentifier != identifier) {
            if (targetIdentifierId.getText().equals(nasmIdentifier.getNameIdentifier().getText())) {
                result.add(nasmIdentifier);
            }
        }
    }
    return result;
}
 
Example #25
Source Project: intellij-xquery   Author: ligasgr   File: XQueryFunctionPrefixReferenceTest.java    License: Apache License 2.0 5 votes vote down vote up
public void testFunctionPrefixReferenceForPredeclaredNamespace() {
    myFixture.configureByFiles("FunctionPrefixReferenceForPredeclaredNamespace.xq");

    PsiElement resolvedReference = getTargetOfReferenceAtCaret(myFixture, XQueryPrefix.class);

    PsiElement originalElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
    XQueryPrefix sourceOfReference = PsiTreeUtil.getParentOfType(originalElement, XQueryPrefix.class);
    assertEquals(resolvedReference, sourceOfReference);
}
 
Example #26
Source Project: intellij-plugin-v4   Author: antlr   File: MyPsiUtils.java    License: BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
public static PsiElement createLeafFromText(Project project, PsiElement context,
											String text, IElementType type)
{
	PsiFileFactoryImpl factory = (PsiFileFactoryImpl)PsiFileFactory.getInstance(project);
	PsiElement el = factory.createElementFromText(text,
												  ANTLRv4Language.INSTANCE,
												  type,
												  context);
	return PsiTreeUtil.getDeepestFirst(el); // forces parsing of file!!
	// start rule depends on root passed in
}
 
Example #27
Source Project: reasonml-idea-plugin   Author: reasonml-editor   File: FunctionParsingTest.java    License: MIT License 5 votes vote down vote up
public void testInnerFunction() {
    PsiLet e = first(letExpressions(parseCode("let _ = error => Belt.Array.mapU(errors, (. error) => error##message);")));

    PsiFunction functionOuter = (PsiFunction) e.getBinding().getFirstChild();
    assertEquals("Belt.Array.mapU(errors, (. error) => error##message)", functionOuter.getBody().getText());

    PsiFunction functionInner = PsiTreeUtil.findChildOfType(functionOuter, PsiFunction.class);
    assertEquals("error##message", functionInner.getBody().getText());
}
 
Example #28
Source Project: idea-php-typo3-plugin   Author: cedricziel   File: SignalSlotMethodReference.java    License: MIT License 5 votes vote down vote up
public SignalSlotMethodReference(@NotNull ClassConstantReference classConstantReference, @NotNull StringLiteralExpression subject, TextRange range) {
    super(subject, range);

    this.methodName = subject.getContents();

    ClassReference classReference = PsiTreeUtil.findChildOfType(classConstantReference, ClassReference.class);
    if (classReference == null || classReference.getFQN() == null) {
        classFqn = "";

        return;
    }

    this.classFqn = classReference.getFQN();
}
 
Example #29
Source Project: idea-php-symfony2-plugin   Author: Haehnchen   File: XmlServiceSuggestIntentionAction.java    License: MIT License 5 votes vote down vote up
@Override
public void invoke(@NotNull Project project, @NotNull PsiFile psiFile, @Nullable Editor editor, @NotNull PsiElement psiElement, @NotNull PsiElement psiElement1) {
    if(editor == null) {
        return;
    }

    PhpClass phpClass = PhpElementsUtil.getClass(project, expectedClass);
    if(phpClass == null) {
        return;
    }

    Collection<ContainerService> suggestions = ServiceUtil.getServiceSuggestionForPhpClass(phpClass, ContainerCollectionResolver.getServices(project));
    if(suggestions.size() == 0) {
        HintManager.getInstance().showErrorHint(editor, "No suggestion found");
        return;
    }

    XmlTag xmlTag = PsiTreeUtil.getParentOfType(psiElement, XmlTag.class);
    if(xmlTag == null) {
        return;
    }

    ServiceSuggestDialog.create(
        editor,
        ContainerUtil.map(suggestions, ContainerService::getName),
        new XmlServiceSuggestIntention.MyInsertCallback(xmlTag)
    );
}
 
Example #30
Source Project: intellij-haskforce   Author: carymrobbins   File: GhcMod.java    License: Apache License 2.0 5 votes vote down vote up
/** The text range of our annotation should be based on the element at that offset. */
@Nullable
private TextRange getTextRange(@NotNull PsiFile psiFile) {
    final String text = psiFile.getText();
    final int offsetStart = getOffsetStart(text);
    if (offsetStart == -1) return null;
    PsiElement el = PsiTreeUtil.findElementOfClassAtOffset(psiFile, offsetStart, PsiElement.class, false);
    if (el == null) return null;
    // It's prettier to show the entire import line as unused instead of just the `import` keyword.
    if (isUnusedImport && el.getParent() instanceof HaskellImpdecl) return el.getParent().getTextRange();
    return el.getTextRange();
}