<commit_before>// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:path/path.dart' as path;

import '../analyzer.dart';
import '../ast.dart';

const _desc = r'Prefer relative imports for files in `lib/`.';

const _details = r'''Prefer relative imports for files in `lib/`.

When mixing relative and absolute imports it's possible to create confusion
where the same member gets imported in two different ways. One way to avoid
that is to ensure you consistently use relative imports for files withing the
`lib/` directory.

**GOOD:**

```
import 'bar.dart';
```

**BAD:**

```
import 'package:my_package/bar.dart';
```

''';

class PreferRelativeImports extends LintRule implements NodeLintRule {
  PreferRelativeImports()
      : super(
            name: 'prefer_relative_imports',
            description: _desc,
            details: _details,
            group: Group.errors);

  @override
  void registerNodeProcessors(
      NodeLintRegistry registry, LinterContext context) {
    final visitor = _Visitor(this, context);
    registry.addCompilationUnit(this, visitor);
    registry.addImportDirective(this, visitor);
  }
}

class _Visitor extends SimpleAstVisitor<void> {
  final PreferRelativeImports rule;
  final LinterContext context;

  bool isInLibFolder;

  _Visitor(this.rule, this.context);

  bool isPackageSelfReference(ImportDirective node) {
    // Ignore this compilation unit if it's not in the lib/ folder.
    if (!isInLibFolder) return false;

    // Is it a package: import?
    final importUri = node.uriContent;
    if (importUri?.startsWith('package:') != true) return false;

    final source = node.uriSource;
    if (source == null) return false;

    // todo (pq): context.package.contains(source) should work (but does not)
    return path.isWithin(context.package.root, source.fullName);
  }

  @override
  void visitCompilationUnit(CompilationUnit node) {
    isInLibFolder = isInLibDir(node, context.package);
  }

  @override
  void visitImportDirective(ImportDirective node) {
    if (isPackageSelfReference(node)) {
      rule.reportLint(node.uri);
    }
  }
}<commit_msg>Fix prefer_relative_imports when using path dependencies<commit_after>// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:path/path.dart' as path;

import '../analyzer.dart';
import '../ast.dart';
import 'implementation_imports.dart' show samePackage;

const _desc = r'Prefer relative imports for files in `lib/`.';

const _details = r'''Prefer relative imports for files in `lib/`.

When mixing relative and absolute imports it's possible to create confusion
where the same member gets imported in two different ways. One way to avoid
that is to ensure you consistently use relative imports for files withing the
`lib/` directory.

**GOOD:**

```
import 'bar.dart';
```

**BAD:**

```
import 'package:my_package/bar.dart';
```

''';

class PreferRelativeImports extends LintRule implements NodeLintRule {
  PreferRelativeImports()
      : super(
            name: 'prefer_relative_imports',
            description: _desc,
            details: _details,
            group: Group.errors);

  @override
  void registerNodeProcessors(
      NodeLintRegistry registry, LinterContext context) {
    final visitor = _Visitor(this, context);
    registry.addCompilationUnit(this, visitor);
    registry.addImportDirective(this, visitor);
  }
}

class _Visitor extends SimpleAstVisitor<void> {
  final PreferRelativeImports rule;
  final LinterContext context;

  bool isInLibFolder;

  _Visitor(this.rule, this.context);

  bool isPackageSelfReference(ImportDirective node) {
    // Ignore this compilation unit if it's not in the lib/ folder.
    if (!isInLibFolder) return false;

    // Is it a package: import?
    final importUriContent = node.uriContent;
    if (importUriContent?.startsWith('package:') != true) return false;

    final source = node.uriSource;
    if (source == null) return false;

    final importUri = node?.uriSource?.uri;
    final sourceUri = node?.element?.source?.uri;
    if (!samePackage(importUri, sourceUri)) return false;

    // todo (pq): context.package.contains(source) should work (but does not)
    return path.isWithin(context.package.root, source.fullName);
  }

  @override
  void visitCompilationUnit(CompilationUnit node) {
    isInLibFolder = isInLibDir(node, context.package);
  }

  @override
  void visitImportDirective(ImportDirective node) {
    if (isPackageSelfReference(node)) {
      rule.reportLint(node.uri);
    }
  }
}
{'fraction_non_alphanumeric': 0.1039141665010928, 'fraction_numerical': 0.0015895092390224518, 'mean_word_length': 3.859073359073359, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5439511', 'n_tokens_mistral': 1505, 'n_tokens_neox': 1459, 'n_words': 464}