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

Add helper to convert Symbol to SymbolReference #1220

Merged
merged 2 commits into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,73 @@ public String relativize(String namespace) {
return this.namespace.equals(namespace) ? name : toString();
}

/**
* Converts the symbol to a {@link SymbolReference} using the given {@code alias}.
*
* @param alias Alias to use to refer to the symbol.
* @param options Variadic array of {@link SymbolReference.Option}s.
* @return Returns the created SymbolReference.
*/
public SymbolReference toReference(String alias, SymbolReference.Option... options) {
return SymbolReference.builder()
.alias(alias)
.symbol(this)
.options(options)
.build();
}

/**
* Converts the symbol to a {@link Symbol} that refers to this Symbol
* using a {@link SymbolReference}. This makes it easier to refer to a
* type using an alias but still through a Symbol to be compatible with
* {@link SymbolProvider}.
*
* <p>The following example creates a Symbol that is referred to as
* "__Document" in code, but is an alias of "foo.Document".
*
* <pre>{@code
* Symbol aliasedSymbol = Symbol.builder()
* .name("Document")
* .namespace("foo", ".")
* .build()
* .toReferenceSymbol("__Document");
* }</pre>
*
* <p>When used with a {@link SymbolWriter}, the writer should add an
* import on "foo.Document" and alias it to "__Document".
*
* <p>The created symbol uses an empty namespace (""). If this is not
* compatible with specific {@link ImportContainer}s to understand that
* the aliased symbol itself needs no imports, then you can augment the
* symbol with other metadata by instead using {@link #toReferencedSymbolBuilder(String)}.
*
* <p>Note that this does not work with every programming language.
* For example, Java does not support aliasing whereas TypeScript does.
*
* @param alias Alias to use to refer to the symbol.
* @return Returns the created Symbol.
* @see #toReferencedSymbolBuilder(String)
*/
public Symbol toReferencedSymbol(String alias) {
return toReferencedSymbolBuilder(alias).build();
}

/**
* Converts the symbol to a {@link Symbol.Builder} that refers to this
* Symbol using a {@link SymbolReference} via an alias. This makes it
* easier to refer to type using an alias but still use a Symbol to be
* compatible with SymbolProviders.
*
* @param alias Alias to use to refer to the symbol.
* @return Returns a SymbolBuilder that is prepared with the symbol and alias.
* @see #toReferencedSymbol(String)
*/
public Symbol.Builder toReferencedSymbolBuilder(String alias) {
return builder()
.name(alias)
.addReference(toReference(alias, SymbolReference.ContextOption.USE));
}

/**
* Gets the list of symbols that are referenced by this symbol.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
package software.amazon.smithy.codegen.core;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -114,4 +116,37 @@ public void canAddDependencies() {
assertThat(symbol.getDependencies(), containsInAnyOrder(a, b));
assertThat(symbol.toBuilder().build(), equalTo(symbol));
}

@Test
public void convertsToAliasedSymbolReference() {
Symbol symbol = Symbol.builder()
.name("foo")
.namespace("bar", ".")
.build();
SymbolReference reference = symbol.toReference("__foo", SymbolReference.ContextOption.DECLARE);

assertThat(reference.getSymbol(), is(symbol));
assertThat(reference.getAlias(), equalTo("__foo"));
assertThat(reference.getOptions(), contains(SymbolReference.ContextOption.DECLARE));
}

@Test
public void convertsToAliasedSymbol() {
Symbol symbol = Symbol.builder()
.name("foo")
.namespace("bar", ".")
.build();

Symbol symbolRef = symbol.toReferencedSymbol("__foo");

SymbolReference ref = SymbolReference.builder()
.alias("__foo")
.symbol(symbol)
.options(SymbolReference.ContextOption.USE)
.build();

assertThat(symbolRef.getName(), equalTo("__foo"));
assertThat(symbolRef.getNamespace(), equalTo(""));
assertThat(symbolRef.getReferences(), contains(ref));
}
}