Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get library prefix for a type? #109

Closed
tejainece opened this issue Nov 20, 2016 · 8 comments
Closed

How to get library prefix for a type? #109

tejainece opened this issue Nov 20, 2016 · 8 comments
Labels
type-question A question about expected behavior or functionality

Comments

@tejainece
Copy link

library 'package:somelib/somelib.dart' as some;

some.SomeClass value;

How to find that SomeClass has prefix of some when you have instance of SomeClass's DartType.

@kevmoo kevmoo added the type-question A question about expected behavior or functionality label Nov 21, 2016
@kevmoo
Copy link
Member

kevmoo commented Nov 21, 2016

CC @jakemac53 @natebosch

@natebosch
Copy link
Member

I don't think you can get an import prefix from the DartType.

Am I correct in assuming you're getting the DartType from a VariableElement for value?

If so I think what you can do is:

String findTypePrefix(VariableElement variable) {
  var declaration = variable.computeNode();
  var typeName = declaration.parent.type.name;
  if (typeName is PrefixedIdentifier) {
    return typeName.prefix;
  }
  return '';
}

Note that depending on how the AnalysisContext is set up and what library contains the variable the call to computeNode() might fail at runtime. If you're using the BarbackResolvers from the build_barback package this should succeed but may be slow. You're most likely on an older version of the build package which has the same Resolvers by default.

@natebosch
Copy link
Member

cc @bwilkerson @stereotype441

Is there a better way to find the import prefix without going through computeNode()?

@stereotype441
Copy link
Member

It depends what you mean by "find the import prefix". If you mean "figure out what import prefix was used in the declaration to refer to the type", then there is no better way than going back to the AST (either using computeNode, or maybe you still have the AST stored away from some other analysis you did). The DartType doesn't record the prefix you used, because in terms of Dart semantics it's irrelevant.

If instead you mean "I want to generate some code that refers to the type, and I don't know whether I should use a prefix or not", then there is a better option: first ask the DartType for its element and find the LibraryElement it's contained in--this tells you the library the type is defined in. Then look at the imports for the code you're generating, find the import that points to that LibraryElement, and see what its prefix is. (If you are generating a file from scratch, then presumably you know what you are importing. If you are generating a file by tweaking an existing file, then you should be able to use the LibraryElement for that file, and look at the import elements it contains). This should be much faster and future-proof than using computeNode.

One thing to be careful about, though: due to strong mode type inference, it's possible for the type of something in a file to refer to a type which is not accessible via an import. So the answer to "what prefix should I use to refer to this type" might be "sorry, you can't". Consider:

File a.dart:
  class A { ... }
File b.dart:
  import "a.dart";
  class _B { ... }
  A f() { ... }
  _B g() { ... }
File c.dart:
  import "b.dart"
  var x = f();
  var y = g();

Now, if you ask analyzer to tell you the type of x, you'll get a DartType representing class A. But if you want to know what prefix you can use to refer to class A, the answer is "you can't refer to class A directly unless you add an import statement."

The situation is worse for y. If you ask analyzer to tell you the type of y, you'll get a DartType representing class _B, which is private to file b.dart. If you want to know what prefix you can use to refer to class B, the answer is "you can't refer to class B directly, not even if you add an import statement, because it's private to a different file."

Hope that helps.

@matanlurey
Copy link
Contributor

@stereotype441 Unless I misunderstand, can't Namespace|NamespaceBuilder be used?

Maybe that is newer than when you commented originally though.

/cc @bwilkerson

@stereotype441
Copy link
Member

@matanlurey It all depends what you are trying to do. The original questioner didn't provide enough details for me to understand the use case.

If you are generating code, and you have a DartType, and you want to know, "what prefix do I need to emit in order to produce a valid reference to this DartType", then using the element model to find the library is probably your best answer, because when you're generating code that means that the analyzer probably hasn't analyzed it yet, so you don't have a Namespace or NamespaceBuilder for the current file.

If you are trying to produce a helpful error message describing a DartType, then perhaps Namespace or could do what you want (though it is not ideal since it maps from name to element, and you want to go the other way). Keep in mind my cautions from above though (the type in question might not be in any namespace).

@matanlurey
Copy link
Contributor

Thanks @stereotype441. I'm closing this since there hasn't been action in a bit.

@xuanswe
Copy link

xuanswe commented Apr 18, 2020

If you are generating code, and you have a DartType, and you want to know, "what prefix do I need to emit in order to produce a valid reference to this DartType", then using the element model to find the library is probably your best answer

Hello @matanlurey, I can get the list of library prefixes. But how could I know which one is the one I need for a type?

Example:

import 'body.dart' as pb;
import 'comment.dart' as pc;

class Body() {
}

@MyAnnotation()
class Todo extends Body implements pb.Body, pc.Comment {}

I want to generate code for class Todo. The generated code need to access to all static fields of all classes Todo, Body, pb.Body and pc.Comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-question A question about expected behavior or functionality
Projects
None yet
Development

No branches or pull requests

6 participants